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 +114 -63
- package/dist/textmode.esm.js +45 -46
- package/dist/textmode.esm.min.js +48 -49
- package/dist/textmode.umd.js +13 -13
- package/dist/textmode.umd.min.js +4 -4
- package/dist/types/Textmode.d.ts +2 -6
- package/dist/types/textmode/Textmodifier.d.ts +8 -6
- package/dist/types/textmode/mixins/AnimationMixin.d.ts +10 -6
- package/dist/types/textmode/mixins/ExportMixin.d.ts +5 -5
- package/dist/types/textmode/mixins/FontMixin.d.ts +1 -1
- package/dist/types/textmode/mixins/RenderingMixin.d.ts +51 -39
- package/package.json +8 -4
package/README.md
CHANGED
|
@@ -10,32 +10,36 @@
|
|
|
10
10
|
|
|
11
11
|
</div>
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
textmode.js is a lightweight creative-coding library for real‑time 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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
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 `
|
|
37
|
-
- A `<canvas>`
|
|
38
|
-
-
|
|
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
|
|
47
|
-
| **Standard ESM
|
|
48
|
-
| **Minified UMD
|
|
49
|
-
| **Minified ESM
|
|
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
|
-
-
|
|
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
|
-
|
|
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
|
|
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
|
-
<
|
|
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
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
|
|
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
|
-
|
|
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
|
-
|
|
183
|
+
> [!NOTE]
|
|
184
|
+
> If you see the version number printed in the console, your installation was successful!
|
|
129
185
|
|
|
130
|
-
##
|
|
186
|
+
## Next steps
|
|
131
187
|
|
|
132
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
package/dist/textmode.esm.js
CHANGED
|
@@ -62,8 +62,8 @@ const v = class v {
|
|
|
62
62
|
}
|
|
63
63
|
};
|
|
64
64
|
n(v, "o", null);
|
|
65
|
-
let
|
|
66
|
-
const _ =
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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, "
|
|
773
|
-
n(this, "
|
|
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.
|
|
794
|
+
this.St = A, A && (this.Tt = {});
|
|
795
795
|
}
|
|
796
796
|
Kt(A, t) {
|
|
797
|
-
this.
|
|
797
|
+
this.Tt[A] = t;
|
|
798
798
|
}
|
|
799
799
|
Zt(A) {
|
|
800
|
-
Object.assign(this.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
1649
|
+
SB(A) {
|
|
1650
1650
|
return A.replace(/[<>:"/\\|?*]/g, "_").replace(/\s+/g, "_").replace(/_{2,}/g, "_").replace(/^_+|_+$/g, "").substring(0, 255);
|
|
1651
1651
|
}
|
|
1652
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
1890
|
-
return t === ".txt" || t.length <= 4 ? this.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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, "
|
|
2066
|
-
n(this, "
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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;
|