textmode.js 0.2.0-beta.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,32 +10,36 @@
10
10
 
11
11
  </div>
12
12
 
13
- `textmode.js` is a free, lightweight and framework-agnostic creative coding library for real-time ASCII art and textmode experiences in web browsers.
13
+ textmode.js is a lightweight creative-coding library for realtime ASCII and textmode graphics in the browser. It combines a grid‑based API with a modern `WebGL2` pipeline, multiple render targets, and aggressive instanced rendering to deliver smooth, high‑performance rendering.
14
14
 
15
- Transform any `<canvas>` or `<video>` element into dynamic ASCII representations with blazing-fast WebGL rendering. Whether you're using p5.js, three.js, or vanilla JavaScript, textmode.js seamlessly integrates with your existing projects to create interactive textmode games, live visual performances, and artistic installations.
15
+ The library is designed to be easy to use and accessible to developers of all skill levels. Whether you're a seasoned developer or just starting out, `textmode.js` provides a simple and intuitive API that makes it easy to create stunning textmode art and animations.
16
16
 
17
- For standalone projects, textmode.js provides its own p5.js-inspired drawing API, letting you create compelling ASCII experiences without additional dependencies.
18
-
19
- The library powers live coding performances, interactive installations, and digital art projects worldwide, bringing the nostalgic aesthetic of textmode art into modern web development.
17
+ Key ideas in one sentence: you draw with simple shape calls; under the hood we batch instances and write to a special framebuffer with five render targets; a conversion pass maps those buffers to a crisp grid of characters on the canvas.
20
18
 
21
19
  ## Features
22
- - **Dependency-free**: No external libraries required, making it lightweight and easy to integrate into any project.
23
- - **TTF/OTF font support**: Load and use TrueType and OpenType fonts for rendering textmode art, allowing for a wide range of styles and characters.
24
- - **Framework-agnostic**: Use `textmode.js` with any JavaScript framework or library, such as `p5.js`, `three.js`, or even vanilla JavaScript.
25
- - **Standalone drawing API**: Use the built-in `p5.js`-like drawing API for creating textmode art without any other dependencies.
26
- - **Injectable**: Easily inject `textmode.js` into websites like YouTube to convert `<video>` or `<canvas>` elements into textmode representations for a unique viewing experience.
27
- - **WebGL1/WebGL2 support**: All shader code provided by `textmode.js` is written in `GLSL ES 1.0`, making it compatible with both `WebGL1` and `WebGL2` contexts, allowing for a wide range of devices to run your ASCII projects.
28
- - **Exporting**: Export your creations to various image formats, and as `.txt`, `.svg` and image files for easy sharing, printing and plotting.
29
- - **Typescript support**: Fully typed library with TypeScript definitions, making it easy to integrate into TypeScript projects and ensuring type safety.
20
+ - Real‑time* ASCII/textmode rendering with a simple drawing API
21
+ - `WebGL2` pipeline with [Multiple Render Targets (MRT)](https://en.wikipedia.org/wiki/Multiple_Render_Targets) for rich per‑cell data
22
+ - Instanced rendering and batching for low draw call counts
23
+ - Font system with runtime font loading and dynamic sizing
24
+ - Author custom filter shaders in [`GLSL ES 3.00`](https://registry.khronos.org/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf) for advanced effects
25
+ - Flexible exporting: TXT, SVG, and raster images *(PNG/JPG/WebP)*
26
+ - Animation loop control: `frameRate`, `loop`/`noLoop`, `redraw`, `frameCount`, etc.
27
+ - Zero dependencies, written in TypeScript, with comprehensive type definitions
28
+
29
+ > [!NOTE]
30
+ > *Performance depends on the complexity of your scene and device capabilities. Consider authoring filter shaders for complex effects at low cost.
30
31
 
31
32
  ## Installation
32
33
 
33
34
  ### Prerequisites
34
35
 
35
36
  To get started with `textmode.js`, you'll need:
36
- - A **modern web browser** with `WebGL` support
37
- - A `<canvas>` or `<video>` element in your project *(optional, for capturing content from a different source)*
38
- - **Node.js 16+** and `npm` *(optional, for ESM installation)*
37
+ - A **modern web browser** with `WebGL2` support *(Chrome, Firefox, Safari, Edge, etc.)*
38
+ - A [`<canvas>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas) in your project *(optional, otherwise the library will create one for you)*
39
+ - [Node.js 16+](https://nodejs.org/) and `npm` *(optional, for ESM installation)*
40
+
41
+ > [!IMPORTANT]
42
+ > `textmode.js` is currently fully dependent on `WebGL2`. Ensure your target browsers support it. You can check compatibility on [caniuse.com](https://caniuse.com/webgl2).
39
43
 
40
44
  ### Importing `textmode.js`
41
45
 
@@ -43,28 +47,31 @@ To get started with `textmode.js`, you'll need:
43
47
 
44
48
  | Bundle type | File size | Font included? | Best for |
45
49
  |-------------|-----------|---------------|----------|
46
- | **Standard UMD**<br/>(`textmode.umd.js`) | ~111kB | ✅ [UrsaFont](https://ursafrank.itch.io/ursafont) embedded | Quick setup, prototyping |
47
- | **Standard ESM**<br/>(`textmode.esm.js`) | ~128kB | ✅ [UrsaFont](https://ursafrank.itch.io/ursafont) embedded | Quick setup, prototyping |
48
- | **Minified UMD**<br/>(`textmode.umd.min.js`) | ~64kB | ❌ Requires external font | Production apps, custom fonts |
49
- | **Minified ESM**<br/>(`textmode.esm.min.js`) | ~82kB | ❌ Requires external font | Production apps, custom fonts |
50
+ | **Standard UMD** (`textmode.umd.js`) | ~112kB | ✅ [UrsaFont](https://ursafrank.itch.io/ursafont) embedded | Quick setup, prototyping |
51
+ | **Standard ESM** (`textmode.esm.js`) | ~130kB | ✅ [UrsaFont](https://ursafrank.itch.io/ursafont) embedded | Quick setup, prototyping |
52
+ | **Minified UMD** (`textmode.umd.min.js`) | ~65kB | ❌ Requires external font | Custom fonts |
53
+ | **Minified ESM** (`textmode.esm.min.js`) | ~84kB | ❌ Requires external font | Custom fonts |
50
54
 
51
55
  **Choose standard bundles for:**
52
56
  - Quick setup with no additional configuration
53
- - Everything embedded and ready to use
54
- - Getting started without worrying about fonts
57
+ - Production applications that use the embedded font
55
58
 
56
59
  **Choose minified bundles for:**
57
60
  - Production applications that don't use the embedded font
58
61
 
59
- #### UMD
62
+ > [!NOTE]
63
+ > Apart from the font inclusion, both bundle types are functionally identical and equally minified.
64
+
65
+ ### UMD
60
66
 
61
67
  To use `textmode.js` in a UMD environment, download the latest `umd` build from the [**GitHub releases page**](https://github.com/humanbydefinition/textmode.js/releases/) or import it directly from a CDN like [**jsDelivr**](https://www.jsdelivr.com/package/npm/textmode.js). The library is distributed as a single JavaScript file, which you can include in your project by adding the following script tag to your HTML file:
62
68
 
63
69
  ```html
70
+ <!-- index.html -->
64
71
  <!DOCTYPE html>
65
72
  <html>
66
73
  <head>
67
- <title>textmode.js example</title>
74
+ <title>textmode.js sketch</title>
68
75
 
69
76
  <!-- Standard bundle (with embedded UrsaFont) -->
70
77
  <script src="https://cdn.jsdelivr.net/npm/textmode.js@latest/dist/textmode.umd.js"></script>
@@ -73,26 +80,40 @@ To use `textmode.js` in a UMD environment, download the latest `umd` build from
73
80
  <!-- <script src="https://cdn.jsdelivr.net/npm/textmode.js@latest/dist/textmode.umd.min.js"></script> -->
74
81
  </head>
75
82
  <body>
76
- <canvas id="myCanvas" width="800" height="600"></canvas>
77
- <script>
78
- (async () => {
79
- // Reference your existing canvas element
80
- const canvas = document.querySelector('canvas#myCanvas');
81
-
82
- // Standard bundle - no font configuration needed
83
- const textmodifier = await textmode.create(canvas);
84
-
85
- // Minified bundle - font required
86
- // const textmodifier = await textmode.create(canvas, {
87
- // fontSource: './path/to/your/font.ttf'
88
- // });
89
- })();
90
- </script>
83
+ <script src="sketch.js"></script>
91
84
  </body>
92
85
  </html>
93
86
  ```
94
87
 
95
- #### ESM
88
+ ```javascript
89
+ // sketch.js
90
+ const t = textmode.create({
91
+ width: window.innerWidth,
92
+ height: window.innerHeight,
93
+ fontSize: 16,
94
+ frameRate: 60
95
+ });
96
+
97
+ t.setup(() => {
98
+ // Optional setup code here (e.g., load fonts/shaders, initialize variables that access 't')
99
+ });
100
+
101
+ t.draw(() => {
102
+ t.background(32); // Dark gray background
103
+
104
+ t.char('A');
105
+ t.charColor(255, 0, 0); // Cover the top-left quarter of the grid with a rectangle of red 'A's
106
+ t.rect(0, 0, t.grid.cols / 2, t.grid.rows / 2);
107
+
108
+ // ...add your drawing code here!
109
+ });
110
+
111
+ t.windowResized(() => {
112
+ t.resizeCanvas(window.innerWidth, window.innerHeight);
113
+ });
114
+ ```
115
+
116
+ ### ESM
96
117
 
97
118
  To use `textmode.js` in an ESM environment, you can install it via `npm`:
98
119
 
@@ -102,43 +123,73 @@ npm install textmode.js
102
123
 
103
124
  Then, you can import it in your JavaScript or TypeScript files:
104
125
 
126
+ ```html
127
+ <!-- index.html -->
128
+ <!DOCTYPE html>
129
+ <html lang="en">
130
+ <head>
131
+ <meta charset="utf-8">
132
+ <title>textmode.js sketch</title>
133
+ </head>
134
+ <body>
135
+ <script type="module" src="./sketch.js"></script>
136
+ </body>
137
+ </html>
138
+ ```
139
+
105
140
  ```javascript
141
+ // sketch.js
106
142
  // Standard bundle (with embedded UrsaFont)
107
143
  import { textmode } from 'textmode.js';
108
144
 
109
145
  // OR Minified bundle (requires external font)
110
146
  // import { textmode } from 'textmode.js/min';
111
147
 
112
- (async () => {
113
- // Canvas example
114
- const canvas = document.querySelector('canvas#myCanvas');
115
-
116
- // Standard bundle - no font configuration needed
117
- const textmodifier = await textmode.create(canvas);
118
-
119
- // Minified bundle - font required
120
- // const textmodifier = await textmode.create(canvas, {
121
- // fontSource: './path/to/your/font.ttf'
122
- // });
123
- })();
148
+ const t = textmode.create({
149
+ width: window.innerWidth,
150
+ height: window.innerHeight,
151
+ fontSize: 16,
152
+ frameRate: 60
153
+ });
154
+
155
+ t.setup(() => {
156
+ // Optional setup code here (e.g., load fonts/shaders, initialize variables that access 't')
157
+ });
158
+
159
+ t.draw(() => {
160
+ t.background(32); // Dark gray background
161
+
162
+ t.char('A');
163
+ t.charColor(255, 0, 0); // Cover the top-left quarter of the grid with a rectangle of red 'A's
164
+ t.rect(0, 0, t.grid.cols / 2, t.grid.rows / 2);
165
+
166
+ // ...add your drawing code here!
167
+ });
168
+
169
+ t.windowResized(() => {
170
+ t.resizeCanvas(window.innerWidth, window.innerHeight);
171
+ });
124
172
  ```
125
173
 
126
- ### Next steps
174
+ ## Verification
175
+
176
+ To verify your installation is working correctly, try this simple test:
177
+
178
+ ```javascript
179
+ // Test if textmode.js is available
180
+ console.log('textmode.js version:', textmode.version);
181
+ ```
127
182
 
128
- Now that you have `textmode.js` set up, you can start creating your ASCII art projects! Check out the [**API documentation**](/api/) for detailed information on how to use the library, including examples and advanced features.
183
+ > [!NOTE]
184
+ > If you see the version number printed in the console, your installation was successful!
129
185
 
130
- ## Learn more
186
+ ## Next steps
131
187
 
132
- ### 📚 [Visit the Official Documentation](https://code.textmode.art/)
188
+ Now that you have `textmode.js` set up, you can start creating your textmode art projects! Going forward, here are some resources to help you get the most out of the library:
133
189
 
134
- Explore the comprehensive documentation at [code.textmode.art](https://code.textmode.art/) for:
135
- - Detailed guides
136
- - Interactive examples
137
- - Complete API reference
138
- - Tips and tricks
139
- - ... and much more!
190
+ 📚 **[Visit the Official Documentation](https://code.textmode.art/)** for detailed guides, interactive examples, complete API reference, tips and tricks, and much more to unlock the full potential of `textmode.js` in your creative coding projects.
140
191
 
141
- The documentation will help you unlock the full potential of `textmode.js` in your creative coding projects.
192
+ 🎨 **[Try the Web Editor](https://editor.textmode.art)** to experiment with `textmode.js` without setting up a local environment.
142
193
 
143
194
  ## Acknowledgements
144
195
 
@@ -62,8 +62,8 @@ const v = class v {
62
62
  }
63
63
  };
64
64
  n(v, "o", null);
65
- let F = v;
66
- const _ = F.D(), V = /* @__PURE__ */ new WeakMap();
65
+ let S = v;
66
+ const _ = S.D(), V = /* @__PURE__ */ new WeakMap();
67
67
  function G(E, A) {
68
68
  V.set(E, A);
69
69
  }
@@ -348,7 +348,7 @@ class tA {
348
348
  n(this, "RA", /* @__PURE__ */ new Map());
349
349
  this.m = A;
350
350
  }
351
- TA(A, t, e, s) {
351
+ SA(A, t, e, s) {
352
352
  const r = this.m;
353
353
  let i = this.RA.get(A);
354
354
  i || (i = /* @__PURE__ */ new Map(), this.RA.set(A, i));
@@ -362,7 +362,7 @@ class tA {
362
362
  }
363
363
  r.bindVertexArray(B);
364
364
  }
365
- SA() {
365
+ TA() {
366
366
  this.m.bindVertexArray(null);
367
367
  }
368
368
  W() {
@@ -388,9 +388,9 @@ class eA {
388
388
  if (!a || !a.HA()) return;
389
389
  const g = a.unitGeometry, l = a.unitBuffer;
390
390
  try {
391
- this.FA.TA(s.QA, a.type + "", g, l), a.batch.WA(s), a.batch.JA(g.primitiveType, g.vertexCount);
391
+ this.FA.SA(s.QA, a.type + "", g, l), a.batch.WA(s), a.batch.JA(g.primitiveType, g.vertexCount);
392
392
  } finally {
393
- a.batch.VA(s), this.FA.SA(), a.KA();
393
+ a.batch.VA(s), this.FA.TA(), a.KA();
394
394
  }
395
395
  };
396
396
  let o = null, h = null;
@@ -419,9 +419,9 @@ class eA {
419
419
  if (s.jA({ x: 0, y: 0, width: g.width, height: g.height }, l), s.HA()) {
420
420
  const u = s.unitGeometry, M = s.unitBuffer;
421
421
  try {
422
- this.FA.TA(o.QA, s.type + "", u, M), s.batch.WA(o), s.batch.JA(u.primitiveType, u.vertexCount);
422
+ this.FA.SA(o.QA, s.type + "", u, M), s.batch.WA(o), s.batch.JA(u.primitiveType, u.vertexCount);
423
423
  } finally {
424
- s.batch.VA(o), this.FA.SA(), s.KA();
424
+ s.batch.VA(o), this.FA.TA(), s.KA();
425
425
  }
426
426
  }
427
427
  g.H();
@@ -433,9 +433,9 @@ class eA {
433
433
  if (s.jA({ x: d, y: I, width: w, height: p }, e), s.HA()) {
434
434
  const u = s.unitGeometry, M = s.unitBuffer;
435
435
  try {
436
- this.FA.TA(c.QA, s.type + "", u, M), s.batch.WA(c), s.batch.JA(u.primitiveType, u.vertexCount);
436
+ this.FA.SA(c.QA, s.type + "", u, M), s.batch.WA(c), s.batch.JA(u.primitiveType, u.vertexCount);
437
437
  } finally {
438
- s.batch.VA(c), this.FA.SA(), s.KA();
438
+ s.batch.VA(c), this.FA.TA(), s.KA();
439
439
  }
440
440
  }
441
441
  A.shader.AA();
@@ -769,8 +769,8 @@ class DA {
769
769
  constructor(A) {
770
770
  n(this, "m");
771
771
  n(this, "Rt", null);
772
- n(this, "Tt", null);
773
- n(this, "St", {});
772
+ n(this, "St", null);
773
+ n(this, "Tt", {});
774
774
  n(this, "Ft", null);
775
775
  n(this, "Ot", /* @__PURE__ */ new Map());
776
776
  n(this, "Ut");
@@ -791,13 +791,13 @@ class DA {
791
791
  return new z(this.m, A, t);
792
792
  }
793
793
  Vt(A) {
794
- this.Tt = A, A && (this.St = {});
794
+ this.St = A, A && (this.Tt = {});
795
795
  }
796
796
  Kt(A, t) {
797
- this.St[A] = t;
797
+ this.Tt[A] = t;
798
798
  }
799
799
  Zt(A) {
800
- Object.assign(this.St, A);
800
+ Object.assign(this.Tt, A);
801
801
  }
802
802
  jt(A) {
803
803
  return new z(this.m, L, A);
@@ -810,7 +810,7 @@ class DA {
810
810
  c !== -1 && (r.enableVertexAttribArray(c), r.vertexAttribPointer(c, 2, r.FLOAT, !1, 8, 0)), r.drawArrays(r.TRIANGLES, 0, 6), c !== -1 && r.disableVertexAttribArray(c);
811
811
  }
812
812
  Nt(A, t, e, s) {
813
- this.Tt ? (this.Lt.st(A, t, e, s, this.Tt, { ...this.St }, this.kt), this.Tt = null, this.St = {}) : this.Lt.Bt(A, t, e, s, this.kt);
813
+ this.St ? (this.Lt.st(A, t, e, s, this.St, { ...this.Tt }, this.kt), this.St = null, this.Tt = {}) : this.Lt.Bt(A, t, e, s, this.kt);
814
814
  }
815
815
  qt(A, t, e, s) {
816
816
  this.Lt.it(A, t, e, s, this.kt.lineWeight, this.kt);
@@ -1011,7 +1011,7 @@ const f = { readShort: (E, A) => (f.t.uint16[0] = E[A] << 8 | E[A + 1], f.t.int1
1011
1011
  }
1012
1012
  return null;
1013
1013
  }, T: N, B: f };
1014
- class S {
1014
+ class F {
1015
1015
  constructor() {
1016
1016
  n(this, "ae", /* @__PURE__ */ new Map());
1017
1017
  n(this, "he", /* @__PURE__ */ new Map());
@@ -1150,7 +1150,7 @@ class dA {
1150
1150
  class wA {
1151
1151
  constructor() {
1152
1152
  n(this, "$e");
1153
- const A = new S();
1153
+ const A = new F();
1154
1154
  this.$e = new dA(A);
1155
1155
  }
1156
1156
  extractCharacters(A) {
@@ -1172,18 +1172,18 @@ class mA {
1172
1172
  n(this, "Ye");
1173
1173
  n(this, "ze");
1174
1174
  n(this, "Re");
1175
- this.ze = A, this.Re = new S(), this.Me = document.createElement("canvas"), this.Ye = this.Me.getContext("2d", { willReadFrequently: !0, alpha: !1 });
1175
+ this.ze = A, this.Re = new F(), this.Me = document.createElement("canvas"), this.Ye = this.Me.getContext("2d", { willReadFrequently: !0, alpha: !1 });
1176
1176
  }
1177
1177
  createTextureAtlas(A, t, e, s) {
1178
1178
  const r = A.length, i = Math.ceil(Math.sqrt(r)), B = Math.ceil(r / i), Q = t.width * i, o = t.height * B, h = typeof s == "object" ? s : null;
1179
- this.Te(Q, o), this.Se(A, t, i, e, h);
1179
+ this.Se(Q, o), this.Te(A, t, i, e, h);
1180
1180
  const a = this.ze.Be(Q, o, 1, { filter: "nearest" });
1181
1181
  return a.F(this.Me), { framebuffer: a, columns: i, rows: B };
1182
1182
  }
1183
- Te(A, t) {
1183
+ Se(A, t) {
1184
1184
  this.Me.width = A, this.Me.height = t, this.Me.style.width = A + "px", this.Me.style.height = A + "px", this.Ye.imageSmoothingEnabled = !1, this.Me.style.imageRendering = "pixelated", this.Ye.fillStyle = "black", this.Ye.fillRect(0, 0, A, t), this.Ye.textBaseline = "top", this.Ye.textAlign = "left", this.Ye.fillStyle = "white";
1185
1185
  }
1186
- Se(A, t, e, s, r) {
1186
+ Te(A, t, e, s, r) {
1187
1187
  const i = s / r.head.unitsPerEm;
1188
1188
  for (let B = 0; B < A.length; B++) {
1189
1189
  const Q = B % e, o = Math.floor(B / e), h = A[B].character, a = this.Fe(r, h);
@@ -1245,7 +1245,7 @@ class mA {
1245
1245
  class pA {
1246
1246
  constructor() {
1247
1247
  n(this, "fe");
1248
- this.fe = new S();
1248
+ this.fe = new F();
1249
1249
  }
1250
1250
  calculateMaxGlyphDimensions(A, t, e) {
1251
1251
  let s = 0;
@@ -1272,7 +1272,7 @@ class pA {
1272
1272
  class yA {
1273
1273
  constructor() {
1274
1274
  n(this, "Re");
1275
- this.Re = new S();
1275
+ this.Re = new F();
1276
1276
  }
1277
1277
  createCharacterObjects(A, t) {
1278
1278
  return A.map((e, s) => {
@@ -1646,10 +1646,10 @@ class W {
1646
1646
  const A = /* @__PURE__ */ new Date();
1647
1647
  return { date: A.toISOString().split("T")[0], time: A.toTimeString().split(" ")[0].replace(/:/g, "-") };
1648
1648
  }
1649
- TB(A) {
1649
+ SB(A) {
1650
1650
  return A.replace(/[<>:"/\\|?*]/g, "_").replace(/\s+/g, "_").replace(/_{2,}/g, "_").replace(/^_+|_+$/g, "").substring(0, 255);
1651
1651
  }
1652
- SB() {
1652
+ TB() {
1653
1653
  return "textmode-export-" + this.zB();
1654
1654
  }
1655
1655
  }
@@ -1827,10 +1827,10 @@ class YA extends W {
1827
1827
  return this.MB(A, "image/svg+xml;charset=utf-8");
1828
1828
  }
1829
1829
  ss(A, t) {
1830
- this.YB(A, this.TB(t) + ".svg", "image/svg+xml;charset=utf-8");
1830
+ this.YB(A, this.SB(t) + ".svg", "image/svg+xml;charset=utf-8");
1831
1831
  }
1832
1832
  Qs(A, t) {
1833
- this.ss(A, t || this.SB());
1833
+ this.ss(A, t || this.TB());
1834
1834
  }
1835
1835
  }
1836
1836
  class H {
@@ -1841,7 +1841,7 @@ class H {
1841
1841
  this.rs = new MA(), this.Es = new GA(), this.ns = new YA();
1842
1842
  }
1843
1843
  gs(A) {
1844
- return { includeBackgroundRectangles: A.includeBackgroundRectangles ?? !0, drawMode: A.drawMode ?? "fill", strokeWidth: A.strokeWidth ?? 1, backgroundColor: A.backgroundColor ?? [0, 0, 0, 0], filename: A.filename || this.ns.SB() };
1844
+ return { includeBackgroundRectangles: A.includeBackgroundRectangles ?? !0, drawMode: A.drawMode ?? "fill", strokeWidth: A.strokeWidth ?? 1, backgroundColor: A.backgroundColor ?? [0, 0, 0, 0], filename: A.filename || this.ns.TB() };
1845
1845
  }
1846
1846
  hs(A, t = {}) {
1847
1847
  const e = this.rs.UB(this.rs.bB(A.pipeline), A.grid), s = this.Es.ts(e, A.grid, A.font, this.gs(t));
@@ -1851,7 +1851,7 @@ class H {
1851
1851
  this.ns.Qs(this.hs(A, t), t.filename);
1852
1852
  }
1853
1853
  }
1854
- class SA extends O {
1854
+ class FA extends O {
1855
1855
  cs(A, t, e, s = " ") {
1856
1856
  var B;
1857
1857
  const r = [];
@@ -1867,7 +1867,7 @@ class SA extends O {
1867
1867
  return r;
1868
1868
  }
1869
1869
  }
1870
- class FA {
1870
+ class SA {
1871
1871
  Cs(A, t) {
1872
1872
  const e = [];
1873
1873
  for (const r of A) {
@@ -1886,8 +1886,8 @@ class zA extends W {
1886
1886
  this.YB(A, e, "text/plain;charset=utf-8");
1887
1887
  }
1888
1888
  ls(A) {
1889
- let t = this.TB(A);
1890
- return t === ".txt" || t.length <= 4 ? this.SB() : t;
1889
+ let t = this.SB(A);
1890
+ return t === ".txt" || t.length <= 4 ? this.TB() : t;
1891
1891
  }
1892
1892
  }
1893
1893
  class X {
@@ -1895,10 +1895,10 @@ class X {
1895
1895
  n(this, "rs");
1896
1896
  n(this, "Es");
1897
1897
  n(this, "ns");
1898
- this.rs = new SA(), this.Es = new FA(), this.ns = new zA();
1898
+ this.rs = new FA(), this.Es = new SA(), this.ns = new zA();
1899
1899
  }
1900
1900
  gs(A) {
1901
- return { preserveTrailingSpaces: A.preserveTrailingSpaces ?? !1, lineEnding: A.lineEnding ?? "lf", emptyCharacter: A.emptyCharacter ?? " ", filename: A.filename || this.ns.SB() };
1901
+ return { preserveTrailingSpaces: A.preserveTrailingSpaces ?? !1, lineEnding: A.lineEnding ?? "lf", emptyCharacter: A.emptyCharacter ?? " ", filename: A.filename || this.ns.TB() };
1902
1902
  }
1903
1903
  Ps(A, t = {}) {
1904
1904
  const e = this.gs(t), s = this.rs.cs(this.rs.bB(A.pipeline), A.grid, A.font, e.emptyCharacter);
@@ -1945,7 +1945,7 @@ class LA {
1945
1945
  const OA = { png: "image/png", jpg: "image/jpeg", webp: "image/webp" }, J = { png: ".png", jpg: ".jpg", webp: ".webp" };
1946
1946
  class WA extends W {
1947
1947
  ds(A, t, e) {
1948
- this.ps(A, this.TB(t) + J[e]);
1948
+ this.ps(A, this.SB(t) + J[e]);
1949
1949
  }
1950
1950
  ps(A, t) {
1951
1951
  const e = URL.createObjectURL(A);
@@ -1968,7 +1968,7 @@ class $A {
1968
1968
  this.rs = new UA(), this.Es = new LA(), this.ns = new WA();
1969
1969
  }
1970
1970
  gs(A) {
1971
- return { format: A.format ?? "png", quality: A.quality ?? 1, scale: A.scale ?? 1, backgroundColor: A.backgroundColor ?? "transparent", filename: A.filename || this.ns.SB() };
1971
+ return { format: A.format ?? "png", quality: A.quality ?? 1, scale: A.scale ?? 1, backgroundColor: A.backgroundColor ?? "transparent", filename: A.filename || this.ns.TB() };
1972
1972
  }
1973
1973
  vs(A) {
1974
1974
  if (!this.ns._s(A.format)) throw Error(`Saving '${A.format}' files is not supported`);
@@ -2062,8 +2062,8 @@ class JA extends function(t, ...e) {
2062
2062
  }(XA, TA, kA, NA, HA) {
2063
2063
  constructor(t = {}) {
2064
2064
  super();
2065
- n(this, "Ts", !1);
2066
- n(this, "Ss", () => {
2065
+ n(this, "Ss", !1);
2066
+ n(this, "Ts", () => {
2067
2067
  });
2068
2068
  n(this, "Fs", () => {
2069
2069
  });
@@ -2076,7 +2076,7 @@ precision highp float;in vec2 v_uv;in vec3 v_character;in vec4 v_primaryColor;in
2076
2076
  async Ls(t) {
2077
2077
  await this.We.BB(t.fontSource);
2078
2078
  const e = this.We.maxGlyphDimensions;
2079
- this.Ms = new vA(this.aB.canvas, e.width, e.height), this.$s = this.ze.Be(this.Ms.cols, this.Ms.rows, 5), this.ks(), this.Ss(), this.Ys.start(() => this.zs());
2079
+ this.Ms = new vA(this.aB.canvas, e.width, e.height), this.$s = this.ze.Be(this.Ms.cols, this.Ms.rows, 5), this.ks(), this.Ts(), this.Ys.start(() => this.zs());
2080
2080
  }
2081
2081
  ks() {
2082
2082
  this.Us = () => {
@@ -2084,13 +2084,13 @@ precision highp float;in vec2 v_uv;in vec3 v_character;in vec4 v_primaryColor;in
2084
2084
  }, window.addEventListener("resize", this.Us);
2085
2085
  }
2086
2086
  zs() {
2087
- if (this.Ys.measureFrameRate(), this.Ys.incrementFrame(), this.Ts) return;
2087
+ if (this.Ys.measureFrameRate(), this.Ys.incrementFrame(), this.Ss) return;
2088
2088
  this.$s.k(), this.ze.Wt(this.Gs), this.Fs(), this.ze.re(this.Gs), this.$s.H();
2089
2089
  const t = this.ze.state.canvasBackgroundColor;
2090
2090
  this.ze.ot(t[0], t[1], t[2], t[3]), this.ze.Wt(this.Rs), this.Rs.eA({ u_characterTexture: this.We.fontFramebuffer, u_charsetDimensions: [this.We.textureColumns, this.We.textureRows], u_asciiCharacterTexture: this.$s.textures[0], u_primaryColorTexture: this.$s.textures[1], u_secondaryColorTexture: this.$s.textures[2], u_transformTexture: this.$s.textures[4], u_rotationTexture: this.$s.textures[3], u_gridCellDimensions: [this.Ms.cols, this.Ms.rows], u_gridPixelDimensions: [this.Ms.width, this.Ms.height], u_gridOffsetPixels: [this.Ms.offsetX, this.Ms.offsetY], u_aspectRatio: this.Ms.width / this.Ms.height }), this.ze.Xt(this.Ms.offsetX, this.Ms.offsetY, this.Ms.width, this.Ms.height);
2091
2091
  }
2092
2092
  setup(t) {
2093
- this.Ss = t;
2093
+ this.Ts = t;
2094
2094
  }
2095
2095
  draw(t) {
2096
2096
  this.Fs = t;
@@ -2102,7 +2102,7 @@ precision highp float;in vec2 v_uv;in vec3 v_character;in vec4 v_primaryColor;in
2102
2102
  this.aB.O(t, e), this.Ms.fA(), this.$s.O(this.Ms.cols, this.Ms.rows), this.ze.Qe(), this.zs();
2103
2103
  }
2104
2104
  destroy() {
2105
- this.Ts || (this.Ys.stop(), window.removeEventListener("resize", this.Us), this.We.W(), this.ze.W(), this.Ts = !0);
2105
+ this.Ss || (this.Ys.stop(), window.removeEventListener("resize", this.Us), this.We.W(), this.ze.W(), this.Ss = !0);
2106
2106
  }
2107
2107
  get grid() {
2108
2108
  return this.Ms;
@@ -2120,7 +2120,7 @@ precision highp float;in vec2 v_uv;in vec3 v_character;in vec4 v_primaryColor;in
2120
2120
  return this.aB.canvas;
2121
2121
  }
2122
2122
  get isDisposed() {
2123
- return this.Ts;
2123
+ return this.Ss;
2124
2124
  }
2125
2125
  get drawFramebuffer() {
2126
2126
  return this.$s;
@@ -2128,7 +2128,6 @@ precision highp float;in vec2 v_uv;in vec3 v_character;in vec4 v_primaryColor;in
2128
2128
  }
2129
2129
  class $ {
2130
2130
  constructor() {
2131
- throw new m("Textmode is a static class and cannot be instantiated.");
2132
2131
  }
2133
2132
  static create(A = {}) {
2134
2133
  return new JA(A);
@@ -2137,7 +2136,7 @@ class $ {
2137
2136
  _.u(A);
2138
2137
  }
2139
2138
  static get version() {
2140
- return "0.2.0-beta.5";
2139
+ return "0.2.0";
2141
2140
  }
2142
2141
  }
2143
2142
  const jA = Object.freeze(Object.defineProperty({ __proto__: null }, Symbol.toStringTag, { value: "Module" })), ZA = $.create, KA = $.setErrorLevel, qA = $.version;