@micahdb/tscon 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,92 @@
1
+ import { Canvas } from "./canvas.ts";
2
+ import type { Glyphs } from "./glyphs.ts";
3
+ import type { Rect } from "./rect.ts";
4
+ /**
5
+ * Renders a character grid from glyphs onto a {@link Canvas}.
6
+ *
7
+ * `Terminal` owns a `rows` x `cols` framebuffer of packed 16-bit glyph
8
+ * cells (as produced by {@link textGlyphs}) and draws it one instanced
9
+ * quad per cell. A frame is typically: {@link clear}, {@link blit} one or
10
+ * more {@link Glyphs} blocks onto the framebuffer, then {@link draw}.
11
+ *
12
+ * If {@link detail_text} is set, it is rendered onto the last row as a
13
+ * status line each frame.
14
+ */
15
+ export declare class Terminal {
16
+ private gl_program;
17
+ private attributes;
18
+ private uniforms;
19
+ private vao;
20
+ private vbo;
21
+ private fbcon;
22
+ private resized;
23
+ private last_detail_text;
24
+ private detail_glyphs;
25
+ /** The {@link Canvas} this terminal renders into. */
26
+ canvas: Canvas;
27
+ /**
28
+ * Status text shown on the bottom row, or `""` for none.
29
+ *
30
+ * When non-empty it is compiled to glyphs (with a bright-on-black
31
+ * style) and blitted across the last row each {@link draw}. Components
32
+ * use this to show hover details, link URLs, etc.
33
+ */
34
+ detail_text: string;
35
+ /**
36
+ * Whether to use {@link Canvas.user_font} for non-box glyphs when
37
+ * available. Set to `true` by the application after assigning a font
38
+ * texture to `canvas.user_font`; automatically falls back to the bitmap
39
+ * font if `user_font` is `null`.
40
+ */
41
+ use_user_font: boolean;
42
+ /**
43
+ * Initializes the terminal for use.
44
+ * Listens for `"resize"` events from the canvas.
45
+ *
46
+ * @param canvas The canvas to render into.
47
+ */
48
+ constructor(canvas: Canvas);
49
+ /**
50
+ * Copy a region of a {@link Glyphs} block onto the console framebuffer.
51
+ *
52
+ * `src` selects the region of `glyphs` to copy and `dst` selects where
53
+ * on the console it goes. `src` and `dst` must be the same size;
54
+ * otherwise the blit is skipped. Both rectangles are clipped to their
55
+ * respective bounds, with negative origins handled by shifting both
56
+ * `src` and `dst` together, so partial off-screen copies work as
57
+ * expected.
58
+ *
59
+ * This only writes to the in-memory framebuffer; call {@link draw} to
60
+ * rasterise it.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * terminal.blit(content,
65
+ * { row: 0, col: 0, rows: content.rows, cols: content.cols },
66
+ * { row: 2, col: 4, rows: content.rows, cols: content.cols });
67
+ * ```
68
+ *
69
+ * @param glyphs Source glyph grid.
70
+ * @param src Region of `glyphs` to copy.
71
+ * @param dst Destination region on the console.
72
+ */
73
+ blit(glyphs: Glyphs, src: Rect, dst: Rect): void;
74
+ /**
75
+ * Clears the framebuffer. If the canvas has been resized since the
76
+ * last clear, the framebuffer is reallocated to the new `rows` x
77
+ * `cols` size. Resets {@link detail_text} to `""`.
78
+ *
79
+ * Call at the start of each frame, before blitting content.
80
+ */
81
+ clear(): void;
82
+ /**
83
+ * Rasterise the console framebuffer to the canvas.
84
+ *
85
+ * If {@link detail_text} changed since the last draw it is recompiled
86
+ * to glyphs and blitted across the bottom row. Then the framebuffer
87
+ * is uploaded and drawn.
88
+ *
89
+ * Call this once per frame after all {@link blit} calls are done.
90
+ */
91
+ draw(): void;
92
+ }
@@ -0,0 +1,275 @@
1
+ import { terminal_frag, terminal_vert } from "./shaders.js";
2
+ import { Canvas } from "./canvas.js";
3
+ import { textGlyphs } from "./glyphs.js";
4
+ import { compileProgram, getAttribLocations, getUniformLocations, } from "./program.js";
5
+ /**
6
+ * Renders a character grid from glyphs onto a {@link Canvas}.
7
+ *
8
+ * `Terminal` owns a `rows` x `cols` framebuffer of packed 16-bit glyph
9
+ * cells (as produced by {@link textGlyphs}) and draws it one instanced
10
+ * quad per cell. A frame is typically: {@link clear}, {@link blit} one or
11
+ * more {@link Glyphs} blocks onto the framebuffer, then {@link draw}.
12
+ *
13
+ * If {@link detail_text} is set, it is rendered onto the last row as a
14
+ * status line each frame.
15
+ */
16
+ export class Terminal {
17
+ gl_program;
18
+ attributes;
19
+ uniforms;
20
+ vao;
21
+ vbo;
22
+ // framebuffer of console characters
23
+ fbcon;
24
+ resized;
25
+ last_detail_text;
26
+ detail_glyphs;
27
+ /** The {@link Canvas} this terminal renders into. */
28
+ canvas;
29
+ /**
30
+ * Status text shown on the bottom row, or `""` for none.
31
+ *
32
+ * When non-empty it is compiled to glyphs (with a bright-on-black
33
+ * style) and blitted across the last row each {@link draw}. Components
34
+ * use this to show hover details, link URLs, etc.
35
+ */
36
+ detail_text;
37
+ /**
38
+ * Whether to use {@link Canvas.user_font} for non-box glyphs when
39
+ * available. Set to `true` by the application after assigning a font
40
+ * texture to `canvas.user_font`; automatically falls back to the bitmap
41
+ * font if `user_font` is `null`.
42
+ */
43
+ use_user_font;
44
+ /**
45
+ * Initializes the terminal for use.
46
+ * Listens for `"resize"` events from the canvas.
47
+ *
48
+ * @param canvas The canvas to render into.
49
+ */
50
+ constructor(canvas) {
51
+ this.canvas = canvas;
52
+ const gl = canvas.gl;
53
+ this.fbcon = new Uint16Array(0);
54
+ this.last_detail_text = "";
55
+ this.detail_glyphs = null;
56
+ this.detail_text = "";
57
+ this.gl_program = compileProgram(gl, terminal_vert, terminal_frag);
58
+ this.attributes = getAttribLocations(gl, this.gl_program, {
59
+ colour: "a_colour",
60
+ char_code: "a_char_code",
61
+ });
62
+ this.uniforms = getUniformLocations(gl, this.gl_program, {
63
+ rows: "u_rows",
64
+ cols: "u_cols",
65
+ mouse_row: "u_mouse_row",
66
+ mouse_col: "u_mouse_col",
67
+ palette: "u_palette",
68
+ bitmap_font: "u_bitmap_font",
69
+ user_font: "u_user_font",
70
+ use_user_font: "u_use_user_font",
71
+ });
72
+ const vao = gl.createVertexArray();
73
+ this.vao = vao;
74
+ if (!vao) {
75
+ throw new Error("Could not create vertex array object");
76
+ }
77
+ gl.bindVertexArray(vao);
78
+ const vbo = gl.createBuffer();
79
+ this.vbo = vbo;
80
+ if (!vbo) {
81
+ throw new Error("Could not create vertex buffer");
82
+ }
83
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
84
+ // every vertex in the VBO is a 16-bit integer split like so:
85
+ // [ a_colour | a_char_code ]
86
+ // [ 8 bits | 8 bits ]
87
+ // a_colour
88
+ gl.vertexAttribIPointer(this.attributes.colour, 1, gl.UNSIGNED_BYTE, 2, 1);
89
+ gl.vertexAttribDivisor(this.attributes.colour, 1);
90
+ gl.enableVertexAttribArray(this.attributes.colour);
91
+ // a_char_code
92
+ gl.vertexAttribIPointer(this.attributes.char_code, 1, gl.UNSIGNED_BYTE, 2, 0);
93
+ gl.vertexAttribDivisor(this.attributes.char_code, 1);
94
+ gl.enableVertexAttribArray(this.attributes.char_code);
95
+ gl.bindVertexArray(null);
96
+ gl.useProgram(this.gl_program);
97
+ gl.uniform1i(this.uniforms.rows, this.canvas.rows);
98
+ gl.uniform1i(this.uniforms.cols, this.canvas.cols);
99
+ gl.uniform1i(this.uniforms.mouse_row, -1);
100
+ gl.uniform1i(this.uniforms.mouse_col, -1);
101
+ gl.uniform3fv(this.uniforms.palette, this.canvas.palette);
102
+ gl.uniform1i(this.uniforms.bitmap_font, 0);
103
+ gl.uniform1i(this.uniforms.user_font, 1);
104
+ gl.uniform1i(this.uniforms.use_user_font, 0);
105
+ this.resized = true;
106
+ this.use_user_font = false;
107
+ this.canvas.addEventListener("resize", () => {
108
+ this.resized = true;
109
+ });
110
+ }
111
+ /**
112
+ * Copy a region of a {@link Glyphs} block onto the console framebuffer.
113
+ *
114
+ * `src` selects the region of `glyphs` to copy and `dst` selects where
115
+ * on the console it goes. `src` and `dst` must be the same size;
116
+ * otherwise the blit is skipped. Both rectangles are clipped to their
117
+ * respective bounds, with negative origins handled by shifting both
118
+ * `src` and `dst` together, so partial off-screen copies work as
119
+ * expected.
120
+ *
121
+ * This only writes to the in-memory framebuffer; call {@link draw} to
122
+ * rasterise it.
123
+ *
124
+ * @example
125
+ * ```ts
126
+ * terminal.blit(content,
127
+ * { row: 0, col: 0, rows: content.rows, cols: content.cols },
128
+ * { row: 2, col: 4, rows: content.rows, cols: content.cols });
129
+ * ```
130
+ *
131
+ * @param glyphs Source glyph grid.
132
+ * @param src Region of `glyphs` to copy.
133
+ * @param dst Destination region on the console.
134
+ */
135
+ blit(glyphs, src, dst) {
136
+ // validate the input rects
137
+ if (src.rows !== dst.rows || src.cols !== dst.cols) {
138
+ console.log("Terminal.blit: not blitting due to bad src or dst");
139
+ return;
140
+ }
141
+ // handle negatives
142
+ if (src.row < 0) {
143
+ const drow = Math.abs(src.row);
144
+ src.row = 0;
145
+ src.rows -= drow;
146
+ dst.row += drow;
147
+ dst.rows -= drow;
148
+ }
149
+ if (src.col < 0) {
150
+ const dcol = Math.abs(src.col);
151
+ src.col = 0;
152
+ src.cols -= dcol;
153
+ dst.col += dcol;
154
+ dst.cols -= dcol;
155
+ }
156
+ if (dst.row < 0) {
157
+ const drow = Math.abs(dst.row);
158
+ src.row += drow;
159
+ src.rows -= drow;
160
+ dst.row = 0;
161
+ dst.rows -= drow;
162
+ }
163
+ if (dst.col < 0) {
164
+ const dcol = Math.abs(dst.col);
165
+ src.col += dcol;
166
+ src.cols -= dcol;
167
+ dst.col = 0;
168
+ dst.cols -= dcol;
169
+ }
170
+ // handle overflow
171
+ if (dst.row + dst.rows > this.canvas.rows) {
172
+ const extra_rows = dst.row + dst.rows -
173
+ this.canvas.rows;
174
+ dst.rows -= extra_rows;
175
+ src.rows = dst.rows;
176
+ }
177
+ if (dst.col + dst.cols > this.canvas.cols) {
178
+ const extra_cols = dst.col + dst.cols -
179
+ this.canvas.cols;
180
+ dst.cols -= extra_cols;
181
+ src.cols = dst.cols;
182
+ }
183
+ for (let row = 0;; row++) {
184
+ const src_row = row + src.row;
185
+ const dst_row = row + dst.row;
186
+ if (src_row >= src.row + src.rows ||
187
+ dst_row >= dst.row + dst.rows) {
188
+ break;
189
+ }
190
+ const src_idx = src_row * glyphs.cols + src.col;
191
+ const dst_idx = dst_row * this.canvas.cols + dst.col;
192
+ this.fbcon.set(glyphs.data.subarray(src_idx, src_idx + src.cols), dst_idx);
193
+ }
194
+ }
195
+ /**
196
+ * Clears the framebuffer. If the canvas has been resized since the
197
+ * last clear, the framebuffer is reallocated to the new `rows` x
198
+ * `cols` size. Resets {@link detail_text} to `""`.
199
+ *
200
+ * Call at the start of each frame, before blitting content.
201
+ */
202
+ clear() {
203
+ const gl = this.canvas.gl;
204
+ if (this.resized) {
205
+ this.resized = false;
206
+ gl.useProgram(this.gl_program);
207
+ gl.uniform1i(this.uniforms.rows, this.canvas.rows);
208
+ gl.uniform1i(this.uniforms.cols, this.canvas.cols);
209
+ this.fbcon = new Uint16Array(this.canvas.rows * this.canvas.cols);
210
+ }
211
+ this.fbcon.fill(0);
212
+ this.detail_text = "";
213
+ }
214
+ /**
215
+ * Rasterise the console framebuffer to the canvas.
216
+ *
217
+ * If {@link detail_text} changed since the last draw it is recompiled
218
+ * to glyphs and blitted across the bottom row. Then the framebuffer
219
+ * is uploaded and drawn.
220
+ *
221
+ * Call this once per frame after all {@link blit} calls are done.
222
+ */
223
+ draw() {
224
+ if (this.last_detail_text !== this.detail_text) {
225
+ this.last_detail_text = this.detail_text;
226
+ if (this.detail_text.length > 0) {
227
+ this.detail_glyphs = textGlyphs("\\B0\\F7" + this.detail_text, this.detail_text.length, false);
228
+ }
229
+ else {
230
+ this.detail_glyphs = null;
231
+ }
232
+ }
233
+ if (this.detail_text.length > 0 &&
234
+ this.detail_glyphs !== null) {
235
+ this.blit(this.detail_glyphs, {
236
+ row: 0,
237
+ col: 0,
238
+ rows: 1,
239
+ cols: this.detail_glyphs.cols,
240
+ }, {
241
+ row: this.canvas.rows - 1,
242
+ col: 0,
243
+ rows: 1,
244
+ cols: this.detail_glyphs.cols,
245
+ });
246
+ }
247
+ const gl = this.canvas.gl;
248
+ gl.useProgram(this.gl_program);
249
+ // set mouse position uniforms
250
+ gl.uniform1i(this.uniforms.mouse_row, this.canvas.mouse_row ?? -1);
251
+ gl.uniform1i(this.uniforms.mouse_col, this.canvas.mouse_col ?? -1);
252
+ // upload glyph data to the GPU
253
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
254
+ gl.bufferData(gl.ARRAY_BUFFER, this.fbcon, gl.DYNAMIC_DRAW);
255
+ // bind and activate the bitmap font
256
+ gl.activeTexture(gl.TEXTURE0);
257
+ gl.bindTexture(gl.TEXTURE_2D, this.canvas.bitmap_font);
258
+ // user application-provided font
259
+ if (this.use_user_font) {
260
+ gl.uniform1i(this.uniforms.use_user_font, 1);
261
+ }
262
+ if (this.canvas.user_font !== null) {
263
+ gl.activeTexture(gl.TEXTURE1);
264
+ gl.bindTexture(gl.TEXTURE_2D, this.canvas.user_font);
265
+ }
266
+ else if (this.use_user_font) {
267
+ this.use_user_font = false;
268
+ gl.uniform1i(this.uniforms.use_user_font, 0);
269
+ }
270
+ // draw glyphs: generate 6 vertices (two triangles = one quad) per glyph instance
271
+ gl.bindVertexArray(this.vao);
272
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, this.canvas.rows * this.canvas.cols);
273
+ gl.bindVertexArray(null);
274
+ }
275
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Load an image file from `path` into a mipmapped, linearly-filtered WebGL2
3
+ * texture.
4
+ *
5
+ * The image is decoded via an `Image` element, uploaded to the GL context as
6
+ * an `RGBA`/`UNSIGNED_BYTE` texture with premultiplied alpha, and given
7
+ * `LINEAR_MIPMAP_LINEAR` minification and `LINEAR` magnification filtering so
8
+ * it can be sampled at arbitrary sizes by a shader.
9
+ *
10
+ * The returned texture is suitable for use as the `texture` argument of
11
+ * {@link Renderer.draw} (e.g. a photograph, portrait or rendered scene) or
12
+ * as the `canvas.user_font` application-provided font texture.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { Canvas, loadTexture } from "@micahdb/tscon";
17
+ *
18
+ * const canvas = new Canvas(element);
19
+ * const texture = await loadTexture(canvas.gl, "/images/portrait.jpeg");
20
+ * ```
21
+ *
22
+ * @param gl The WebGL2 context to create the texture on.
23
+ * @param path URL/path of the image to load.
24
+ * @returns A promise that resolves with the created `WebGLTexture` once
25
+ * the image has been decoded and uploaded.
26
+ */
27
+ export declare function loadTexture(gl: WebGL2RenderingContext, path: string): Promise<WebGLTexture>;
28
+ /**
29
+ * Load six images into a mipmapped cube-map texture.
30
+ *
31
+ * Cube maps are used for environment/skybox rendering. The six faces must be
32
+ * supplied in the standard OpenGL cube-map face order:
33
+ *
34
+ * 1. positive X (right)
35
+ * 2. negative X (left)
36
+ * 3. positive Y (top)
37
+ * 4. negative Y (bottom)
38
+ * 5. positive Z (front)
39
+ * 6. negative Z (back)
40
+ *
41
+ * The resulting texture uses `LINEAR_MIPMAP_LINEAR` / `LINEAR` filtering and is
42
+ * suitable for sampling with `samplerCube` in a shader.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * import { Canvas, loadCubeMap } from "@micahdb/tscon";
47
+ *
48
+ * const canvas = new Canvas(element);
49
+ * const skybox = await loadCubeMap(canvas.gl, [
50
+ * "/images/skybox/right.png",
51
+ * "/images/skybox/left.png",
52
+ * "/images/skybox/top.png",
53
+ * "/images/skybox/bottom.png",
54
+ * "/images/skybox/front.png",
55
+ * "/images/skybox/back.png",
56
+ * ]);
57
+ * ```
58
+ *
59
+ * @param gl The WebGL2 context to create the texture on.
60
+ * @param faces Exactly six image URLs, one per cube-map face
61
+ * (see order above).
62
+ * @returns A promise that resolves with the created cube-map texture.
63
+ * @throws If `faces` does not contain exactly six entries or the GL
64
+ * texture cannot be created.
65
+ */
66
+ export declare function loadCubeMap(gl: WebGL2RenderingContext, faces: string[]): Promise<WebGLTexture>;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Load an image file from `path` into a mipmapped, linearly-filtered WebGL2
3
+ * texture.
4
+ *
5
+ * The image is decoded via an `Image` element, uploaded to the GL context as
6
+ * an `RGBA`/`UNSIGNED_BYTE` texture with premultiplied alpha, and given
7
+ * `LINEAR_MIPMAP_LINEAR` minification and `LINEAR` magnification filtering so
8
+ * it can be sampled at arbitrary sizes by a shader.
9
+ *
10
+ * The returned texture is suitable for use as the `texture` argument of
11
+ * {@link Renderer.draw} (e.g. a photograph, portrait or rendered scene) or
12
+ * as the `canvas.user_font` application-provided font texture.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { Canvas, loadTexture } from "@micahdb/tscon";
17
+ *
18
+ * const canvas = new Canvas(element);
19
+ * const texture = await loadTexture(canvas.gl, "/images/portrait.jpeg");
20
+ * ```
21
+ *
22
+ * @param gl The WebGL2 context to create the texture on.
23
+ * @param path URL/path of the image to load.
24
+ * @returns A promise that resolves with the created `WebGLTexture` once
25
+ * the image has been decoded and uploaded.
26
+ */
27
+ export function loadTexture(gl, path) {
28
+ return new Promise((resolve, reject) => {
29
+ const image = new Image();
30
+ image.src = path;
31
+ image.onload = () => {
32
+ const tex = gl.createTexture();
33
+ if (!tex) {
34
+ reject(new Error("When creating GL texture"));
35
+ return;
36
+ }
37
+ gl.bindTexture(gl.TEXTURE_2D, tex);
38
+ // prevent texture halos/outlines from filtering
39
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
40
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
41
+ gl.generateMipmap(gl.TEXTURE_2D);
42
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
43
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
44
+ resolve(tex);
45
+ };
46
+ });
47
+ }
48
+ /**
49
+ * Load six images into a mipmapped cube-map texture.
50
+ *
51
+ * Cube maps are used for environment/skybox rendering. The six faces must be
52
+ * supplied in the standard OpenGL cube-map face order:
53
+ *
54
+ * 1. positive X (right)
55
+ * 2. negative X (left)
56
+ * 3. positive Y (top)
57
+ * 4. negative Y (bottom)
58
+ * 5. positive Z (front)
59
+ * 6. negative Z (back)
60
+ *
61
+ * The resulting texture uses `LINEAR_MIPMAP_LINEAR` / `LINEAR` filtering and is
62
+ * suitable for sampling with `samplerCube` in a shader.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * import { Canvas, loadCubeMap } from "@micahdb/tscon";
67
+ *
68
+ * const canvas = new Canvas(element);
69
+ * const skybox = await loadCubeMap(canvas.gl, [
70
+ * "/images/skybox/right.png",
71
+ * "/images/skybox/left.png",
72
+ * "/images/skybox/top.png",
73
+ * "/images/skybox/bottom.png",
74
+ * "/images/skybox/front.png",
75
+ * "/images/skybox/back.png",
76
+ * ]);
77
+ * ```
78
+ *
79
+ * @param gl The WebGL2 context to create the texture on.
80
+ * @param faces Exactly six image URLs, one per cube-map face
81
+ * (see order above).
82
+ * @returns A promise that resolves with the created cube-map texture.
83
+ * @throws If `faces` does not contain exactly six entries or the GL
84
+ * texture cannot be created.
85
+ */
86
+ export async function loadCubeMap(gl, faces) {
87
+ if (faces.length !== 6) {
88
+ throw new Error("Cube map requires exactly 6 faces");
89
+ }
90
+ const texture = gl.createTexture();
91
+ if (!texture) {
92
+ throw new Error("When creating cube map texture");
93
+ }
94
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
95
+ const targets = [
96
+ gl.TEXTURE_CUBE_MAP_POSITIVE_X,
97
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
98
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
99
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
100
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
101
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
102
+ ];
103
+ const promises = faces.map(async (path, index) => {
104
+ const image = new Promise((resolve, reject) => {
105
+ const img = new Image();
106
+ img.src = path;
107
+ img.onload = () => resolve(img);
108
+ img.onerror = (err) => reject(new Error(`When loading image at ${path}`, { cause: err }));
109
+ });
110
+ const img = await image;
111
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
112
+ gl.texImage2D(targets[index], 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
113
+ });
114
+ await Promise.all(promises);
115
+ gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
116
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
117
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
118
+ return texture;
119
+ }
package/package.json CHANGED
@@ -1,6 +1,45 @@
1
1
  {
2
- "name": "@micahdb/tscon",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@micahdb/tscon",
3
+ "version": "0.1.1",
4
+ "description": "WebGL 2.0 text-mode graphics in TypeScript.",
5
+ "license": "MIT",
6
+ "author": "Micah Baker",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/micahdbak/tscon.git"
10
+ },
11
+ "keywords": [
12
+ "webgl",
13
+ "webgl2",
14
+ "text-mode",
15
+ "terminal",
16
+ "console",
17
+ "cp437",
18
+ "typography",
19
+ "canvas"
20
+ ],
21
+ "type": "module",
22
+ "sideEffects": false,
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "scripts": {
36
+ "lint": "oxlint src scripts",
37
+ "shaders": "bun run scripts/shaders.ts",
38
+ "build": "tsc -p tsconfig.json",
39
+ "prepack": "bun run build"
40
+ },
41
+ "devDependencies": {
42
+ "oxlint": "^1.88.0",
43
+ "typescript": "^7.0.2"
44
+ }
45
+ }