bloody-engine 1.0.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.
@@ -0,0 +1,1940 @@
1
+ import X from "gl";
2
+ import * as C from "fs/promises";
3
+ import * as T from "path";
4
+ class Y {
5
+ constructor(e) {
6
+ this.isBrowser = !0, e.canvas ? this.canvas = e.canvas : (this.canvas = document.createElement("canvas"), document.body.appendChild(this.canvas)), this.width = e.width, this.height = e.height, this.canvas.width = this.width, this.canvas.height = this.height;
7
+ const t = {
8
+ alpha: !1,
9
+ ...e.contextAttributes
10
+ }, r = this.canvas.getContext("webgl", t);
11
+ if (!r)
12
+ throw new Error("Failed to initialize WebGL context in browser");
13
+ this.glContext = r;
14
+ }
15
+ resize(e, t) {
16
+ this.width = e, this.height = t, this.canvas.width = e, this.canvas.height = t, this.glContext.viewport(0, 0, e, t);
17
+ }
18
+ getViewport() {
19
+ return { width: this.width, height: this.height };
20
+ }
21
+ clear(e) {
22
+ e && this.glContext.clearColor(e.r, e.g, e.b, e.a), this.glContext.clear(
23
+ this.glContext.COLOR_BUFFER_BIT | this.glContext.DEPTH_BUFFER_BIT
24
+ );
25
+ }
26
+ present() {
27
+ }
28
+ dispose() {
29
+ this.canvas.parentElement && this.canvas.parentElement.removeChild(this.canvas);
30
+ }
31
+ /**
32
+ * Get the underlying canvas element (browser-specific)
33
+ */
34
+ getCanvas() {
35
+ return this.canvas;
36
+ }
37
+ }
38
+ class G {
39
+ constructor(e) {
40
+ this.isBrowser = !1, this.width = e.width, this.height = e.height;
41
+ const t = X(this.width, this.height, {
42
+ preserveDrawingBuffer: e.preserveDrawingBuffer ?? !0,
43
+ ...e.contextAttributes
44
+ });
45
+ if (!t)
46
+ throw new Error("Failed to initialize WebGL context in Node.js");
47
+ this.glContext = t;
48
+ }
49
+ resize(e, t) {
50
+ this.width = e, this.height = t, console.warn(
51
+ "NodeRenderingContext: Resize requested but not supported. Consider recreating context."
52
+ );
53
+ }
54
+ getViewport() {
55
+ return { width: this.width, height: this.height };
56
+ }
57
+ clear(e) {
58
+ e && this.glContext.clearColor(e.r, e.g, e.b, e.a), this.glContext.clear(
59
+ this.glContext.COLOR_BUFFER_BIT | this.glContext.DEPTH_BUFFER_BIT
60
+ );
61
+ }
62
+ present() {
63
+ this.glContext.flush();
64
+ }
65
+ dispose() {
66
+ this.glContext.flush();
67
+ }
68
+ /**
69
+ * Read the current framebuffer contents as RGBA pixel data
70
+ * Used for capturing frames for display or saving
71
+ */
72
+ readPixels() {
73
+ const e = new Uint8Array(this.width * this.height * 4);
74
+ return this.glContext.readPixels(
75
+ 0,
76
+ 0,
77
+ this.width,
78
+ this.height,
79
+ this.glContext.RGBA,
80
+ this.glContext.UNSIGNED_BYTE,
81
+ e
82
+ ), e;
83
+ }
84
+ }
85
+ class k {
86
+ /**
87
+ * Detect if running in a browser environment
88
+ */
89
+ static isBrowserEnvironment() {
90
+ return typeof window < "u" && typeof document < "u";
91
+ }
92
+ /**
93
+ * Create a rendering context appropriate for the current environment
94
+ */
95
+ static createContext(e) {
96
+ return this.isBrowserEnvironment() ? new Y(e) : new G(e);
97
+ }
98
+ /**
99
+ * Create a browser-specific rendering context
100
+ */
101
+ static createBrowserContext(e) {
102
+ return new Y(e);
103
+ }
104
+ /**
105
+ * Create a Node.js-specific rendering context
106
+ */
107
+ static createNodeContext(e) {
108
+ return new G(e);
109
+ }
110
+ }
111
+ class H {
112
+ /**
113
+ * Create a new shader program
114
+ * @param gl WebGL rendering context
115
+ * @param vertexSource Raw vertex shader source code
116
+ * @param fragmentSource Raw fragment shader source code
117
+ * @param isBrowser Whether running in browser environment (affects precision header)
118
+ */
119
+ constructor(e, t, r, s) {
120
+ this.gl = e;
121
+ const i = this.injectPrecisionHeader(
122
+ t,
123
+ s
124
+ ), o = this.injectPrecisionHeader(
125
+ r,
126
+ s
127
+ );
128
+ this.vertexShader = this.compileShader(
129
+ i,
130
+ e.VERTEX_SHADER
131
+ ), this.fragmentShader = this.compileShader(
132
+ o,
133
+ e.FRAGMENT_SHADER
134
+ ), this.program = this.linkProgram(this.vertexShader, this.fragmentShader);
135
+ }
136
+ /**
137
+ * Inject precision header for ES and desktop OpenGL differences
138
+ * @param source Original shader source
139
+ * @param isBrowser Whether in browser (WebGL ES) or Node (desktop OpenGL)
140
+ * @returns Processed shader source with precision header
141
+ */
142
+ injectPrecisionHeader(e, t) {
143
+ return e.includes("#ifdef GL_ES") || e.includes("precision") ? e : `#ifdef GL_ES
144
+ precision highp float;
145
+ #endif
146
+ ` + e;
147
+ }
148
+ /**
149
+ * Compile a single shader (vertex or fragment)
150
+ * @param source Shader source code
151
+ * @param type gl.VERTEX_SHADER or gl.FRAGMENT_SHADER
152
+ * @returns Compiled shader
153
+ */
154
+ compileShader(e, t) {
155
+ const r = this.gl.createShader(t);
156
+ if (!r)
157
+ throw new Error(`Failed to create shader of type ${t}`);
158
+ if (this.gl.shaderSource(r, e), this.gl.compileShader(r), !this.gl.getShaderParameter(r, this.gl.COMPILE_STATUS)) {
159
+ const i = this.gl.getShaderInfoLog(r), o = t === this.gl.VERTEX_SHADER ? "vertex" : "fragment";
160
+ throw this.gl.deleteShader(r), new Error(
161
+ `Failed to compile ${o} shader:
162
+ ${i}
163
+
164
+ Source:
165
+ ${e}`
166
+ );
167
+ }
168
+ return r;
169
+ }
170
+ /**
171
+ * Link vertex and fragment shaders into a program
172
+ * @param vertexShader Compiled vertex shader
173
+ * @param fragmentShader Compiled fragment shader
174
+ * @returns Linked shader program
175
+ */
176
+ linkProgram(e, t) {
177
+ const r = this.gl.createProgram();
178
+ if (!r)
179
+ throw new Error("Failed to create shader program");
180
+ if (this.gl.attachShader(r, e), this.gl.attachShader(r, t), this.gl.linkProgram(r), !this.gl.getProgramParameter(r, this.gl.LINK_STATUS)) {
181
+ const i = this.gl.getProgramInfoLog(r);
182
+ throw this.gl.deleteProgram(r), this.gl.deleteShader(e), this.gl.deleteShader(t), new Error(`Failed to link shader program:
183
+ ${i}`);
184
+ }
185
+ return r;
186
+ }
187
+ /**
188
+ * Get the compiled shader program
189
+ */
190
+ getProgram() {
191
+ return this.program;
192
+ }
193
+ /**
194
+ * Get uniform location by name
195
+ * @param name Uniform variable name
196
+ */
197
+ getUniformLocation(e) {
198
+ return this.gl.getUniformLocation(this.program, e);
199
+ }
200
+ /**
201
+ * Get attribute location by name
202
+ * @param name Attribute variable name
203
+ */
204
+ getAttributeLocation(e) {
205
+ return this.gl.getAttribLocation(this.program, e);
206
+ }
207
+ /**
208
+ * Use this shader program
209
+ */
210
+ use() {
211
+ this.gl.useProgram(this.program);
212
+ }
213
+ /**
214
+ * Clean up shader resources
215
+ */
216
+ dispose() {
217
+ this.gl.deleteProgram(this.program), this.gl.deleteShader(this.vertexShader), this.gl.deleteShader(this.fragmentShader);
218
+ }
219
+ }
220
+ class W {
221
+ constructor(e, t) {
222
+ this.context = k.createContext({
223
+ width: e,
224
+ height: t,
225
+ preserveDrawingBuffer: !0
226
+ });
227
+ }
228
+ /**
229
+ * Get the underlying WebGL rendering context
230
+ */
231
+ getGLContext() {
232
+ return this.context.glContext;
233
+ }
234
+ /**
235
+ * Get the rendering context
236
+ */
237
+ getRenderingContext() {
238
+ return this.context;
239
+ }
240
+ /**
241
+ * Get current width
242
+ */
243
+ getWidth() {
244
+ return this.context.width;
245
+ }
246
+ /**
247
+ * Get current height
248
+ */
249
+ getHeight() {
250
+ return this.context.height;
251
+ }
252
+ /**
253
+ * Get viewport dimensions
254
+ */
255
+ getViewport() {
256
+ return this.context.getViewport();
257
+ }
258
+ /**
259
+ * Check if running in browser
260
+ */
261
+ isBrowser() {
262
+ return this.context.isBrowser;
263
+ }
264
+ /**
265
+ * Resize the graphics device
266
+ */
267
+ resize(e, t) {
268
+ this.context.resize(e, t);
269
+ }
270
+ /**
271
+ * Clear the rendering surface
272
+ */
273
+ clear(e) {
274
+ this.context.clear(e);
275
+ }
276
+ /**
277
+ * Present the rendered frame
278
+ */
279
+ present() {
280
+ this.context.present();
281
+ }
282
+ /**
283
+ * Cleanup and release resources
284
+ */
285
+ dispose() {
286
+ this.context.dispose();
287
+ }
288
+ /**
289
+ * Create a shader program
290
+ * @param vertexSource Vertex shader source code
291
+ * @param fragmentSource Fragment shader source code
292
+ * @returns Compiled and linked shader program
293
+ */
294
+ createShader(e, t) {
295
+ return new H(
296
+ this.context.glContext,
297
+ e,
298
+ t,
299
+ this.context.isBrowser
300
+ );
301
+ }
302
+ }
303
+ class B {
304
+ /**
305
+ * Create a texture from pixel data
306
+ * @param gl WebGL context
307
+ * @param width Texture width
308
+ * @param height Texture height
309
+ * @param data Pixel data (Uint8Array RGBA)
310
+ */
311
+ constructor(e, t, r, s) {
312
+ this.gl = e, this.width = t, this.height = r;
313
+ const i = e.createTexture();
314
+ if (!i)
315
+ throw new Error("Failed to create texture");
316
+ this.texture = i, e.bindTexture(e.TEXTURE_2D, this.texture), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.LINEAR), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.LINEAR), s ? e.texImage2D(
317
+ e.TEXTURE_2D,
318
+ 0,
319
+ e.RGBA,
320
+ t,
321
+ r,
322
+ 0,
323
+ e.RGBA,
324
+ e.UNSIGNED_BYTE,
325
+ s
326
+ ) : e.texImage2D(
327
+ e.TEXTURE_2D,
328
+ 0,
329
+ e.RGBA,
330
+ t,
331
+ r,
332
+ 0,
333
+ e.RGBA,
334
+ e.UNSIGNED_BYTE,
335
+ null
336
+ ), e.bindTexture(e.TEXTURE_2D, null);
337
+ }
338
+ /**
339
+ * Create a solid color texture
340
+ * @param gl WebGL context
341
+ * @param width Texture width
342
+ * @param height Texture height
343
+ * @param r Red (0-255)
344
+ * @param g Green (0-255)
345
+ * @param b Blue (0-255)
346
+ * @param a Alpha (0-255)
347
+ */
348
+ static createSolid(e, t, r, s, i, o, n = 255) {
349
+ const a = t * r, h = new Uint8Array(a * 4);
350
+ for (let x = 0; x < a; x++) {
351
+ const l = x * 4;
352
+ h[l] = s, h[l + 1] = i, h[l + 2] = o, h[l + 3] = n;
353
+ }
354
+ return new B(e, t, r, h);
355
+ }
356
+ /**
357
+ * Create a checkerboard texture
358
+ * @param gl WebGL context
359
+ * @param width Texture width
360
+ * @param height Texture height
361
+ * @param squareSize Size of each square
362
+ */
363
+ static createCheckerboard(e, t, r, s = 32) {
364
+ const i = new Uint8Array(t * r * 4);
365
+ for (let o = 0; o < r; o++)
366
+ for (let n = 0; n < t; n++) {
367
+ const a = Math.floor(n / s), h = Math.floor(o / s), x = (a + h) % 2 === 0, l = (o * t + n) * 4, d = x ? 255 : 0;
368
+ i[l] = d, i[l + 1] = d, i[l + 2] = d, i[l + 3] = 255;
369
+ }
370
+ return new B(e, t, r, i);
371
+ }
372
+ /**
373
+ * Create a gradient texture
374
+ * @param gl WebGL context
375
+ * @param width Texture width
376
+ * @param height Texture height
377
+ */
378
+ static createGradient(e, t, r) {
379
+ const s = new Uint8Array(t * r * 4);
380
+ for (let i = 0; i < r; i++)
381
+ for (let o = 0; o < t; o++) {
382
+ const n = (i * t + o) * 4;
383
+ s[n] = Math.floor(o / t * 255), s[n + 1] = Math.floor(i / r * 255), s[n + 2] = 128, s[n + 3] = 255;
384
+ }
385
+ return new B(e, t, r, s);
386
+ }
387
+ /**
388
+ * Bind this texture to a texture unit
389
+ * @param unit Texture unit (0-7 typically)
390
+ */
391
+ bind(e = 0) {
392
+ this.gl.activeTexture(this.gl.TEXTURE0 + e), this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
393
+ }
394
+ /**
395
+ * Unbind texture
396
+ */
397
+ unbind() {
398
+ this.gl.bindTexture(this.gl.TEXTURE_2D, null);
399
+ }
400
+ /**
401
+ * Get the underlying WebGL texture
402
+ */
403
+ getHandle() {
404
+ return this.texture;
405
+ }
406
+ /**
407
+ * Get texture dimensions
408
+ */
409
+ getDimensions() {
410
+ return { width: this.width, height: this.height };
411
+ }
412
+ /**
413
+ * Clean up texture resources
414
+ */
415
+ dispose() {
416
+ this.gl.deleteTexture(this.texture);
417
+ }
418
+ }
419
+ class Q {
420
+ constructor(e, t, r = 0) {
421
+ this.gl = e, this.stride = r;
422
+ const s = r > 0 ? r / 4 : 3;
423
+ this.vertexCount = t.length / s;
424
+ const i = e.createBuffer();
425
+ if (!i)
426
+ throw new Error("Failed to create vertex buffer");
427
+ this.buffer = i, e.bindBuffer(e.ARRAY_BUFFER, this.buffer), e.bufferData(e.ARRAY_BUFFER, t, e.STATIC_DRAW), e.bindBuffer(e.ARRAY_BUFFER, null);
428
+ }
429
+ /**
430
+ * Bind buffer for rendering
431
+ */
432
+ bind() {
433
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffer);
434
+ }
435
+ /**
436
+ * Unbind buffer
437
+ */
438
+ unbind() {
439
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
440
+ }
441
+ /**
442
+ * Get vertex count
443
+ */
444
+ getVertexCount() {
445
+ return this.vertexCount;
446
+ }
447
+ /**
448
+ * Get stride
449
+ */
450
+ getStride() {
451
+ return this.stride;
452
+ }
453
+ /**
454
+ * Clean up resources
455
+ */
456
+ dispose() {
457
+ this.gl.deleteBuffer(this.buffer);
458
+ }
459
+ }
460
+ class j {
461
+ constructor(e, t) {
462
+ this.gl = e, this.indexCount = t.length;
463
+ const r = e.createBuffer();
464
+ if (!r)
465
+ throw new Error("Failed to create index buffer");
466
+ this.buffer = r, e.bindBuffer(e.ELEMENT_ARRAY_BUFFER, this.buffer), e.bufferData(e.ELEMENT_ARRAY_BUFFER, t, e.STATIC_DRAW), e.bindBuffer(e.ELEMENT_ARRAY_BUFFER, null);
467
+ }
468
+ /**
469
+ * Bind buffer for rendering
470
+ */
471
+ bind() {
472
+ this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.buffer);
473
+ }
474
+ /**
475
+ * Unbind buffer
476
+ */
477
+ unbind() {
478
+ this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);
479
+ }
480
+ /**
481
+ * Get index count
482
+ */
483
+ getIndexCount() {
484
+ return this.indexCount;
485
+ }
486
+ /**
487
+ * Clean up resources
488
+ */
489
+ dispose() {
490
+ this.gl.deleteBuffer(this.buffer);
491
+ }
492
+ }
493
+ const K = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
494
+ __proto__: null,
495
+ IndexBuffer: j,
496
+ VertexBuffer: Q
497
+ }, Symbol.toStringTag, { value: "Module" }));
498
+ class de {
499
+ /**
500
+ * Create a new batch renderer (V1)
501
+ * @param gl WebGL rendering context
502
+ * @param shader Shader program to use
503
+ * @param maxQuads Maximum number of quads to batch (default 1000)
504
+ */
505
+ constructor(e, t, r = 1e3) {
506
+ this.vertexBuffer = null, this.quads = [], this.isDirty = !1, this.verticesPerQuad = 6, this.floatsPerVertex = 5, this.texture = null, this.gl = e, this.shader = t, this.maxQuads = r;
507
+ const s = r * this.verticesPerQuad * this.floatsPerVertex;
508
+ this.vertexData = new Float32Array(s);
509
+ const i = e.createBuffer();
510
+ if (!i)
511
+ throw new Error("Failed to create vertex buffer");
512
+ this.vertexBuffer = i, e.bindBuffer(e.ARRAY_BUFFER, this.vertexBuffer), e.bufferData(e.ARRAY_BUFFER, this.vertexData.byteLength, e.DYNAMIC_DRAW), e.bindBuffer(e.ARRAY_BUFFER, null);
513
+ }
514
+ /**
515
+ * Set the texture for batch rendering
516
+ * @param texture The texture to use when rendering
517
+ */
518
+ setTexture(e) {
519
+ this.texture = e;
520
+ }
521
+ /**
522
+ * Add a quad to the batch
523
+ * @param quad Quad instance to add
524
+ */
525
+ addQuad(e) {
526
+ if (this.quads.length >= this.maxQuads) {
527
+ console.warn(`Batch renderer at max capacity (${this.maxQuads})`);
528
+ return;
529
+ }
530
+ this.quads.push(e), this.isDirty = !0;
531
+ }
532
+ /**
533
+ * Clear all quads from the batch
534
+ */
535
+ clear() {
536
+ this.quads = [], this.isDirty = !0;
537
+ }
538
+ /**
539
+ * Get number of quads currently in batch
540
+ */
541
+ getQuadCount() {
542
+ return this.quads.length;
543
+ }
544
+ /**
545
+ * Update the batch - rebuilds vertex buffer if quads changed
546
+ */
547
+ update() {
548
+ if (!this.isDirty || this.quads.length === 0)
549
+ return;
550
+ let e = 0;
551
+ for (const t of this.quads) {
552
+ const r = this.generateQuadVertices(t);
553
+ for (const s of r)
554
+ this.vertexData[e++] = s[0], this.vertexData[e++] = s[1], this.vertexData[e++] = s[2], this.vertexData[e++] = s[3], this.vertexData[e++] = s[4];
555
+ }
556
+ this.vertexBuffer && (this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer), this.gl.bufferSubData(
557
+ this.gl.ARRAY_BUFFER,
558
+ 0,
559
+ this.vertexData.subarray(0, e)
560
+ ), this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null)), this.isDirty = !1;
561
+ }
562
+ /**
563
+ * Render the batch
564
+ * @param camera Optional camera for view transform (defaults to identity matrix)
565
+ */
566
+ render(e) {
567
+ if (this.quads.length !== 0 && (this.update(), this.shader.use(), this.vertexBuffer)) {
568
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer);
569
+ const t = this.shader.getAttributeLocation("aPosition"), r = this.shader.getAttributeLocation("aTexCoord");
570
+ if (t !== -1 && (this.gl.enableVertexAttribArray(t), this.gl.vertexAttribPointer(
571
+ t,
572
+ 3,
573
+ // 3 floats (x, y, z)
574
+ this.gl.FLOAT,
575
+ !1,
576
+ this.floatsPerVertex * 4,
577
+ // stride
578
+ 0
579
+ // offset
580
+ )), r !== -1 && (this.gl.enableVertexAttribArray(r), this.gl.vertexAttribPointer(
581
+ r,
582
+ 2,
583
+ // 2 floats (u, v)
584
+ this.gl.FLOAT,
585
+ !1,
586
+ this.floatsPerVertex * 4,
587
+ // stride
588
+ 12
589
+ // offset after position
590
+ )), this.texture) {
591
+ this.texture.bind(0);
592
+ const o = this.shader.getUniformLocation("uTexture");
593
+ o !== null && this.gl.uniform1i(o, 0);
594
+ }
595
+ const s = this.shader.getUniformLocation("uMatrix");
596
+ if (s !== null) {
597
+ const o = e ? e.getViewMatrix() : new Float32Array([
598
+ 1,
599
+ 0,
600
+ 0,
601
+ 0,
602
+ 0,
603
+ 1,
604
+ 0,
605
+ 0,
606
+ 0,
607
+ 0,
608
+ 1,
609
+ 0,
610
+ 0,
611
+ 0,
612
+ 0,
613
+ 1
614
+ ]);
615
+ this.gl.uniformMatrix4fv(s, !1, o);
616
+ }
617
+ const i = this.quads.length * this.verticesPerQuad;
618
+ this.gl.drawArrays(this.gl.TRIANGLES, 0, i), this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
619
+ }
620
+ }
621
+ /**
622
+ * Generate vertices for a quad with rotation applied
623
+ * Returns 6 vertices (2 triangles)
624
+ * @private
625
+ */
626
+ generateQuadVertices(e) {
627
+ const { x: t, y: r, width: s, height: i, rotation: o } = e, n = s / 2, a = i / 2, h = Math.cos(o), x = Math.sin(o), l = (m, v) => [m * h - v * x, m * x + v * h], d = [
628
+ [-n, -a],
629
+ // bottom-left
630
+ [n, -a],
631
+ // bottom-right
632
+ [n, a],
633
+ // top-right
634
+ [n, a],
635
+ // top-right (duplicate)
636
+ [-n, a],
637
+ // top-left
638
+ [-n, -a]
639
+ // bottom-left (duplicate)
640
+ ], f = [
641
+ [0, 0],
642
+ // bottom-left
643
+ [1, 0],
644
+ // bottom-right
645
+ [1, 1],
646
+ // top-right
647
+ [1, 1],
648
+ // top-right
649
+ [0, 1],
650
+ // top-left
651
+ [0, 0]
652
+ // bottom-left
653
+ ], y = [];
654
+ for (let m = 0; m < d.length; m++) {
655
+ const [v, E] = d[m], [A, u] = l(v, E), [w, b] = f[m];
656
+ y.push([t + A, r + u, 0, w, b]);
657
+ }
658
+ return y;
659
+ }
660
+ /**
661
+ * Dispose resources
662
+ */
663
+ dispose() {
664
+ this.vertexBuffer && (this.gl.deleteBuffer(this.vertexBuffer), this.vertexBuffer = null);
665
+ }
666
+ }
667
+ class fe {
668
+ /**
669
+ * Create a new sprite batch renderer (V2)
670
+ * @param gl WebGL rendering context
671
+ * @param shader Shader program to use (should be SHADERS_V2)
672
+ * @param maxQuads Maximum number of quads to batch (default 1000)
673
+ */
674
+ constructor(e, t, r = 1e3) {
675
+ this.vertexBuffer = null, this.quads = [], this.isDirty = !1, this.verticesPerQuad = 6, this.floatsPerVertex = 10, this.texture = null, this.depthTestEnabled = !0, this.gl = e, this.shader = t, this.maxQuads = r;
676
+ const s = r * this.verticesPerQuad * this.floatsPerVertex;
677
+ this.vertexData = new Float32Array(s);
678
+ const i = e.createBuffer();
679
+ if (!i)
680
+ throw new Error("Failed to create vertex buffer");
681
+ this.vertexBuffer = i, e.bindBuffer(e.ARRAY_BUFFER, this.vertexBuffer), e.bufferData(e.ARRAY_BUFFER, this.vertexData.byteLength, e.DYNAMIC_DRAW), e.bindBuffer(e.ARRAY_BUFFER, null);
682
+ }
683
+ /**
684
+ * Set the texture for batch rendering
685
+ * @param texture The texture to use when rendering
686
+ */
687
+ setTexture(e) {
688
+ this.texture = e;
689
+ }
690
+ /**
691
+ * Add a sprite quad to the batch
692
+ * @param quad Sprite quad instance to add
693
+ */
694
+ addQuad(e) {
695
+ if (this.quads.length >= this.maxQuads) {
696
+ console.warn(`Sprite batch renderer at max capacity (${this.maxQuads})`);
697
+ return;
698
+ }
699
+ this.quads.push(e), this.isDirty = !0;
700
+ }
701
+ /**
702
+ * Clear all quads from the batch
703
+ */
704
+ clear() {
705
+ this.quads = [], this.isDirty = !0;
706
+ }
707
+ /**
708
+ * Get number of quads currently in batch
709
+ */
710
+ getQuadCount() {
711
+ return this.quads.length;
712
+ }
713
+ /**
714
+ * Update the batch - rebuilds vertex buffer if quads changed
715
+ */
716
+ update() {
717
+ if (!this.isDirty || this.quads.length === 0)
718
+ return;
719
+ let e = 0;
720
+ for (const t of this.quads) {
721
+ const {
722
+ x: r,
723
+ y: s,
724
+ z: i = 0,
725
+ width: o,
726
+ height: n,
727
+ rotation: a,
728
+ color: h = { r: 1, g: 1, b: 1, a: 1 },
729
+ uvRect: x = { uMin: 0, vMin: 0, uMax: 1, vMax: 1 },
730
+ texIndex: l = 0
731
+ } = t, d = this.generateQuadVertices({
732
+ x: r,
733
+ y: s,
734
+ z: i,
735
+ width: o,
736
+ height: n,
737
+ rotation: a,
738
+ color: h,
739
+ uvRect: x,
740
+ texIndex: l
741
+ });
742
+ for (const f of d)
743
+ this.vertexData[e++] = f.x, this.vertexData[e++] = f.y, this.vertexData[e++] = f.z, this.vertexData[e++] = f.u, this.vertexData[e++] = f.v, this.vertexData[e++] = f.r, this.vertexData[e++] = f.g, this.vertexData[e++] = f.b, this.vertexData[e++] = f.a, this.vertexData[e++] = f.texIndex;
744
+ }
745
+ this.vertexBuffer && (this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer), this.gl.bufferSubData(
746
+ this.gl.ARRAY_BUFFER,
747
+ 0,
748
+ this.vertexData.subarray(0, e)
749
+ ), this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null)), this.isDirty = !1;
750
+ }
751
+ /**
752
+ * Set whether depth testing is enabled
753
+ * When enabled, sprites with lower Z values appear behind sprites with higher Z values
754
+ * @param enabled Whether to enable depth testing (default true)
755
+ */
756
+ setDepthTestEnabled(e) {
757
+ this.depthTestEnabled = e;
758
+ }
759
+ /**
760
+ * Render the batch
761
+ * @param camera Optional camera for view transform (defaults to identity matrix)
762
+ */
763
+ render(e) {
764
+ if (this.quads.length !== 0 && (this.update(), this.shader.use(), this.depthTestEnabled ? (this.gl.enable(this.gl.DEPTH_TEST), this.gl.depthFunc(this.gl.LEQUAL)) : this.gl.disable(this.gl.DEPTH_TEST), this.vertexBuffer)) {
765
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer);
766
+ const t = this.shader.getAttributeLocation("aPosition"), r = this.shader.getAttributeLocation("aTexCoord"), s = this.shader.getAttributeLocation("aColor"), i = this.shader.getAttributeLocation("aTexIndex"), o = this.floatsPerVertex * 4;
767
+ if (t !== -1 && (this.gl.enableVertexAttribArray(t), this.gl.vertexAttribPointer(
768
+ t,
769
+ 3,
770
+ // 3 floats (x, y, z)
771
+ this.gl.FLOAT,
772
+ !1,
773
+ o,
774
+ 0
775
+ // offset
776
+ )), r !== -1 && (this.gl.enableVertexAttribArray(r), this.gl.vertexAttribPointer(
777
+ r,
778
+ 2,
779
+ // 2 floats (u, v)
780
+ this.gl.FLOAT,
781
+ !1,
782
+ o,
783
+ 12
784
+ // offset after position
785
+ )), s !== -1 && (this.gl.enableVertexAttribArray(s), this.gl.vertexAttribPointer(
786
+ s,
787
+ 4,
788
+ // 4 floats (r, g, b, a)
789
+ this.gl.FLOAT,
790
+ !1,
791
+ o,
792
+ 20
793
+ // offset after texCoord
794
+ )), i !== -1 && (this.gl.enableVertexAttribArray(i), this.gl.vertexAttribPointer(
795
+ i,
796
+ 1,
797
+ // 1 float (texIndex)
798
+ this.gl.FLOAT,
799
+ !1,
800
+ o,
801
+ 36
802
+ // offset after color
803
+ )), this.texture) {
804
+ this.texture.bind(0);
805
+ const h = this.shader.getUniformLocation("uTexture");
806
+ h !== null && this.gl.uniform1i(h, 0);
807
+ }
808
+ const n = this.shader.getUniformLocation("uMatrix");
809
+ if (n !== null) {
810
+ const h = e ? e.getViewMatrix() : new Float32Array([
811
+ 1,
812
+ 0,
813
+ 0,
814
+ 0,
815
+ 0,
816
+ 1,
817
+ 0,
818
+ 0,
819
+ 0,
820
+ 0,
821
+ 1,
822
+ 0,
823
+ 0,
824
+ 0,
825
+ 0,
826
+ 1
827
+ ]);
828
+ this.gl.uniformMatrix4fv(n, !1, h);
829
+ }
830
+ const a = this.quads.length * this.verticesPerQuad;
831
+ this.gl.drawArrays(this.gl.TRIANGLES, 0, a), this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
832
+ }
833
+ }
834
+ /**
835
+ * Generate vertices for a quad with rotation applied
836
+ * Returns 6 vertices (2 triangles)
837
+ * @private
838
+ */
839
+ generateQuadVertices(e) {
840
+ const { x: t, y: r, z: s, width: i, height: o, rotation: n, color: a, uvRect: h, texIndex: x } = e, l = i / 2, d = o / 2, f = Math.cos(n), y = Math.sin(n), m = (u, w) => [u * f - w * y, u * y + w * f], v = [
841
+ [-l, -d],
842
+ // bottom-left
843
+ [l, -d],
844
+ // bottom-right
845
+ [l, d],
846
+ // top-right
847
+ [l, d],
848
+ // top-right (duplicate)
849
+ [-l, d],
850
+ // top-left
851
+ [-l, -d]
852
+ // bottom-left (duplicate)
853
+ ], E = [
854
+ [h.uMin, h.vMin],
855
+ // bottom-left
856
+ [h.uMax, h.vMin],
857
+ // bottom-right
858
+ [h.uMax, h.vMax],
859
+ // top-right
860
+ [h.uMax, h.vMax],
861
+ // top-right
862
+ [h.uMin, h.vMax],
863
+ // top-left
864
+ [h.uMin, h.vMin]
865
+ // bottom-left
866
+ ], A = [];
867
+ for (let u = 0; u < v.length; u++) {
868
+ const [w, b] = v[u], [_, D] = m(w, b), [U, g] = E[u];
869
+ A.push({
870
+ x: t + _,
871
+ y: r + D,
872
+ z: s,
873
+ u: U,
874
+ v: g,
875
+ r: a.r,
876
+ g: a.g,
877
+ b: a.b,
878
+ a: a.a,
879
+ texIndex: x
880
+ });
881
+ }
882
+ return A;
883
+ }
884
+ /**
885
+ * Dispose resources
886
+ */
887
+ dispose() {
888
+ this.vertexBuffer && (this.gl.deleteBuffer(this.vertexBuffer), this.vertexBuffer = null);
889
+ }
890
+ }
891
+ class F {
892
+ /**
893
+ * Create an identity matrix
894
+ * @returns 4x4 identity matrix in column-major order
895
+ */
896
+ static identity() {
897
+ return new Float32Array([
898
+ 1,
899
+ 0,
900
+ 0,
901
+ 0,
902
+ // column 0
903
+ 0,
904
+ 1,
905
+ 0,
906
+ 0,
907
+ // column 1
908
+ 0,
909
+ 0,
910
+ 1,
911
+ 0,
912
+ // column 2
913
+ 0,
914
+ 0,
915
+ 0,
916
+ 1
917
+ // column 3
918
+ ]);
919
+ }
920
+ /**
921
+ * Create a translation matrix
922
+ * @param x Translation along X axis
923
+ * @param y Translation along Y axis
924
+ * @param z Translation along Z axis (default 0)
925
+ * @returns 4x4 translation matrix in column-major order
926
+ */
927
+ static translation(e, t, r = 0) {
928
+ return new Float32Array([
929
+ 1,
930
+ 0,
931
+ 0,
932
+ 0,
933
+ // column 0
934
+ 0,
935
+ 1,
936
+ 0,
937
+ 0,
938
+ // column 1
939
+ 0,
940
+ 0,
941
+ 1,
942
+ 0,
943
+ // column 2
944
+ e,
945
+ t,
946
+ r,
947
+ 1
948
+ // column 3
949
+ ]);
950
+ }
951
+ /**
952
+ * Create a scale matrix
953
+ * @param x Scale factor along X axis
954
+ * @param y Scale factor along Y axis
955
+ * @param z Scale factor along Z axis (default 1)
956
+ * @returns 4x4 scale matrix in column-major order
957
+ */
958
+ static scale(e, t, r = 1) {
959
+ return new Float32Array([
960
+ e,
961
+ 0,
962
+ 0,
963
+ 0,
964
+ // column 0
965
+ 0,
966
+ t,
967
+ 0,
968
+ 0,
969
+ // column 1
970
+ 0,
971
+ 0,
972
+ r,
973
+ 0,
974
+ // column 2
975
+ 0,
976
+ 0,
977
+ 0,
978
+ 1
979
+ // column 3
980
+ ]);
981
+ }
982
+ /**
983
+ * Multiply two matrices (result = a * b)
984
+ * @param a First matrix (left operand)
985
+ * @param b Second matrix (right operand)
986
+ * @returns Result of matrix multiplication in column-major order
987
+ */
988
+ static multiply(e, t) {
989
+ const r = new Float32Array(16);
990
+ for (let s = 0; s < 4; s++)
991
+ for (let i = 0; i < 4; i++) {
992
+ let o = 0;
993
+ for (let n = 0; n < 4; n++)
994
+ o += e[n * 4 + i] * t[s * 4 + n];
995
+ r[s * 4 + i] = o;
996
+ }
997
+ return r;
998
+ }
999
+ /**
1000
+ * Create a view matrix from camera position and zoom
1001
+ * The view matrix transforms world coordinates to camera/eye coordinates
1002
+ *
1003
+ * View = Translation(-cameraX, -cameraY, 0) * Scale(zoom, zoom, 1)
1004
+ *
1005
+ * @param x Camera X position (translation will be negative)
1006
+ * @param y Camera Y position (translation will be negative)
1007
+ * @param zoom Camera zoom level (1.0 = no zoom, >1 = zoom in, <1 = zoom out)
1008
+ * @returns 4x4 view matrix in column-major order
1009
+ */
1010
+ static createViewMatrix(e, t, r) {
1011
+ const s = F.translation(-e, -t, 0), i = F.scale(r, r, 1);
1012
+ return F.multiply(s, i);
1013
+ }
1014
+ }
1015
+ class ge {
1016
+ /**
1017
+ * Create a new camera
1018
+ * @param x Initial X position (default 0)
1019
+ * @param y Initial Y position (default 0)
1020
+ * @param zoom Initial zoom level (default 1.0)
1021
+ */
1022
+ constructor(e = 0, t = 0, r = 1) {
1023
+ this._viewMatrix = null, this._viewMatrixDirty = !0, this._x = e, this._y = t, this._zoom = r;
1024
+ }
1025
+ /**
1026
+ * Get the camera X position
1027
+ */
1028
+ get x() {
1029
+ return this._x;
1030
+ }
1031
+ /**
1032
+ * Set the camera X position
1033
+ */
1034
+ set x(e) {
1035
+ this._x = e, this._viewMatrixDirty = !0;
1036
+ }
1037
+ /**
1038
+ * Get the camera Y position
1039
+ */
1040
+ get y() {
1041
+ return this._y;
1042
+ }
1043
+ /**
1044
+ * Set the camera Y position
1045
+ */
1046
+ set y(e) {
1047
+ this._y = e, this._viewMatrixDirty = !0;
1048
+ }
1049
+ /**
1050
+ * Get the camera zoom level
1051
+ */
1052
+ get zoom() {
1053
+ return this._zoom;
1054
+ }
1055
+ /**
1056
+ * Set the camera zoom level
1057
+ * Values: 1.0 = no zoom, >1 = zoom in, <1 = zoom out
1058
+ */
1059
+ set zoom(e) {
1060
+ this._zoom = Math.max(1e-3, e), this._viewMatrixDirty = !0;
1061
+ }
1062
+ /**
1063
+ * Set both X and Y position at once
1064
+ * @param x New X position
1065
+ * @param y New Y position
1066
+ */
1067
+ setPosition(e, t) {
1068
+ this._x = e, this._y = t, this._viewMatrixDirty = !0;
1069
+ }
1070
+ /**
1071
+ * Move the camera by a relative offset
1072
+ * @param dx X offset to add to current position
1073
+ * @param dy Y offset to add to current position
1074
+ */
1075
+ move(e, t) {
1076
+ this._x += e, this._y += t, this._viewMatrixDirty = !0;
1077
+ }
1078
+ /**
1079
+ * Scale the zoom by a factor
1080
+ * @param factor Multiplier for current zoom (e.g., 1.1 to zoom in 10%)
1081
+ */
1082
+ zoomBy(e) {
1083
+ this._zoom = Math.max(1e-3, this._zoom * e), this._viewMatrixDirty = !0;
1084
+ }
1085
+ /**
1086
+ * Reset camera to default position and zoom
1087
+ */
1088
+ reset() {
1089
+ this._x = 0, this._y = 0, this._zoom = 1, this._viewMatrixDirty = !0;
1090
+ }
1091
+ /**
1092
+ * Get the view matrix for this camera
1093
+ * The view matrix transforms world coordinates to camera space
1094
+ * Caches the result until camera properties change
1095
+ *
1096
+ * @returns 4x4 view matrix in column-major order
1097
+ */
1098
+ getViewMatrix() {
1099
+ return (this._viewMatrixDirty || this._viewMatrix === null) && (this._viewMatrix = F.createViewMatrix(this._x, this._y, this._zoom), this._viewMatrixDirty = !1), this._viewMatrix;
1100
+ }
1101
+ /**
1102
+ * Convert screen coordinates to world coordinates
1103
+ * Useful for mouse picking and interaction
1104
+ *
1105
+ * @param screenX Screen X coordinate (pixels)
1106
+ * @param screenY Screen Y coordinate (pixels)
1107
+ * @param viewportWidth Viewport width in pixels
1108
+ * @param viewportHeight Viewport height in pixels
1109
+ * @returns World coordinates {x, y}
1110
+ */
1111
+ screenToWorld(e, t, r, s) {
1112
+ const i = e - r / 2, o = t - s / 2, n = i / this._zoom + this._x, a = o / this._zoom + this._y;
1113
+ return { x: n, y: a };
1114
+ }
1115
+ /**
1116
+ * Convert world coordinates to screen coordinates
1117
+ * Useful for UI positioning and debug rendering
1118
+ *
1119
+ * @param worldX World X coordinate
1120
+ * @param worldY World Y coordinate
1121
+ * @param viewportWidth Viewport width in pixels
1122
+ * @param viewportHeight Viewport height in pixels
1123
+ * @returns Screen coordinates {x, y} in pixels
1124
+ */
1125
+ worldToScreen(e, t, r, s) {
1126
+ const i = (e - this._x) * this._zoom, o = (t - this._y) * this._zoom, n = i + r / 2, a = o + s / 2;
1127
+ return { x: n, y: a };
1128
+ }
1129
+ }
1130
+ class J {
1131
+ /**
1132
+ * Create a new browser resource loader
1133
+ * @param baseUrl Optional base URL for resolving relative paths (defaults to current origin)
1134
+ * @param timeout Default timeout for requests in milliseconds (default: 10000)
1135
+ */
1136
+ constructor(e = "", t = 1e4) {
1137
+ this.baseUrl = e || this.getCurrentOrigin(), this.defaultTimeout = t;
1138
+ }
1139
+ /**
1140
+ * Get the current origin (protocol + host + port)
1141
+ */
1142
+ getCurrentOrigin() {
1143
+ return typeof window < "u" ? window.location.origin : "http://localhost";
1144
+ }
1145
+ /**
1146
+ * Resolve a relative path against the base URL
1147
+ * @param path Relative or absolute path
1148
+ * @returns Resolved absolute URL
1149
+ */
1150
+ resolvePath(e) {
1151
+ try {
1152
+ return e.startsWith("http://") || e.startsWith("https://") ? e : e.startsWith("//") ? window.location.protocol + e : e.startsWith("/") ? this.baseUrl + e : `${this.baseUrl}/${e}`;
1153
+ } catch {
1154
+ return e;
1155
+ }
1156
+ }
1157
+ /**
1158
+ * Load a single resource from a URL
1159
+ * @param path URL or relative path to the resource
1160
+ * @param options Optional loading configuration
1161
+ * @returns Promise resolving to the resource content
1162
+ */
1163
+ async load(e, t) {
1164
+ const r = this.resolvePath(e);
1165
+ try {
1166
+ const s = {
1167
+ credentials: t?.credentials || "same-origin"
1168
+ };
1169
+ t?.headers && (s.headers = t.headers);
1170
+ const i = new AbortController(), o = setTimeout(() => i.abort(), this.defaultTimeout);
1171
+ s.signal = i.signal;
1172
+ const n = await fetch(r, s);
1173
+ if (clearTimeout(o), !n.ok)
1174
+ throw new Error(
1175
+ `HTTP ${n.status}: ${n.statusText} for URL: ${r}`
1176
+ );
1177
+ return await n.text();
1178
+ } catch (s) {
1179
+ throw s instanceof Error ? s.name === "AbortError" ? new Error(
1180
+ `Request timeout after ${this.defaultTimeout}ms for URL: ${r}`
1181
+ ) : new Error(`Failed to load resource from ${r}: ${s.message}`) : new Error(`Failed to load resource from ${r}: Unknown error`);
1182
+ }
1183
+ }
1184
+ /**
1185
+ * Load multiple resources in parallel
1186
+ * @param paths Array of URLs or paths
1187
+ * @param options Optional loading configuration
1188
+ * @returns Promise resolving to array of load results
1189
+ */
1190
+ async loadMultiple(e, t) {
1191
+ const r = e.map(async (s) => {
1192
+ try {
1193
+ return {
1194
+ data: await this.load(s, t),
1195
+ path: s,
1196
+ success: !0
1197
+ };
1198
+ } catch (i) {
1199
+ return {
1200
+ data: "",
1201
+ path: s,
1202
+ success: !1,
1203
+ error: i instanceof Error ? i.message : String(i)
1204
+ };
1205
+ }
1206
+ });
1207
+ return Promise.all(r);
1208
+ }
1209
+ /**
1210
+ * Check if the path is valid for loading in the browser
1211
+ * @param path URL or path to check
1212
+ * @returns true if the path can be loaded
1213
+ */
1214
+ canLoad(e) {
1215
+ const t = [
1216
+ /^https?:\/\//i,
1217
+ // Absolute HTTP(S) URLs
1218
+ /^\/\//,
1219
+ // Protocol-relative URLs
1220
+ /^\//,
1221
+ // Absolute paths
1222
+ /^\.\.?\//
1223
+ // Relative paths starting with ./ or ../
1224
+ ], r = /\.[a-z0-9]+$/i.test(e);
1225
+ return t.some((s) => s.test(e)) || r;
1226
+ }
1227
+ /**
1228
+ * Set a new base URL for resolving relative paths
1229
+ * @param baseUrl New base URL
1230
+ */
1231
+ setBaseUrl(e) {
1232
+ this.baseUrl = e;
1233
+ }
1234
+ /**
1235
+ * Get the current base URL
1236
+ * @returns Current base URL
1237
+ */
1238
+ getBaseUrl() {
1239
+ return this.baseUrl;
1240
+ }
1241
+ /**
1242
+ * Set the default request timeout
1243
+ * @param timeout Timeout in milliseconds
1244
+ */
1245
+ setTimeout(e) {
1246
+ this.defaultTimeout = e;
1247
+ }
1248
+ }
1249
+ const Z = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1250
+ __proto__: null,
1251
+ BrowserResourceLoader: J
1252
+ }, Symbol.toStringTag, { value: "Module" }));
1253
+ class ee {
1254
+ /**
1255
+ * Create a new Node.js resource loader
1256
+ * @param baseDir Optional base directory for resolving relative paths (defaults to current working directory)
1257
+ */
1258
+ constructor(e = process.cwd()) {
1259
+ this.baseDir = e;
1260
+ }
1261
+ /**
1262
+ * Resolve a relative path against the base directory
1263
+ * @param filePath Relative or absolute file path
1264
+ * @returns Resolved absolute file path
1265
+ */
1266
+ resolvePath(e) {
1267
+ return T.isAbsolute(e) ? T.normalize(e) : T.normalize(T.join(this.baseDir, e));
1268
+ }
1269
+ /**
1270
+ * Load a single resource from a file
1271
+ * @param filePath File path (relative or absolute)
1272
+ * @param options Optional loading configuration
1273
+ * @returns Promise resolving to the file content
1274
+ */
1275
+ async load(e, t) {
1276
+ const r = this.resolvePath(e), s = t?.encoding || "utf-8";
1277
+ try {
1278
+ return await C.readFile(r, s);
1279
+ } catch (i) {
1280
+ if (i instanceof Error) {
1281
+ const o = i.code;
1282
+ throw o === "ENOENT" ? new Error(
1283
+ `File not found: ${r} (resolved from: ${e})`
1284
+ ) : o === "EACCES" ? new Error(
1285
+ `Permission denied reading file: ${r}`
1286
+ ) : o === "EISDIR" ? new Error(
1287
+ `Path is a directory, not a file: ${r}`
1288
+ ) : new Error(
1289
+ `Failed to load resource from ${r}: ${i.message}`
1290
+ );
1291
+ }
1292
+ throw new Error(
1293
+ `Failed to load resource from ${r}: Unknown error`
1294
+ );
1295
+ }
1296
+ }
1297
+ /**
1298
+ * Load multiple resources in parallel
1299
+ * @param filePaths Array of file paths
1300
+ * @param options Optional loading configuration
1301
+ * @returns Promise resolving to array of load results
1302
+ */
1303
+ async loadMultiple(e, t) {
1304
+ const r = e.map(async (s) => {
1305
+ try {
1306
+ return {
1307
+ data: await this.load(s, t),
1308
+ path: s,
1309
+ success: !0
1310
+ };
1311
+ } catch (i) {
1312
+ return {
1313
+ data: "",
1314
+ path: s,
1315
+ success: !1,
1316
+ error: i instanceof Error ? i.message : String(i)
1317
+ };
1318
+ }
1319
+ });
1320
+ return Promise.all(r);
1321
+ }
1322
+ /**
1323
+ * Check if the path is valid for loading in Node.js
1324
+ * @param filePath File path to check
1325
+ * @returns true if the path can be loaded
1326
+ */
1327
+ canLoad(e) {
1328
+ return [
1329
+ /^\//,
1330
+ // Unix absolute paths
1331
+ /^[a-zA-Z]:/,
1332
+ // Windows absolute paths (e.g., C:\)
1333
+ /^\.\.?\//,
1334
+ // Relative paths starting with ./ or ../
1335
+ /^[^/\\]+\//
1336
+ // Relative paths without explicit prefix (e.g., "shaders/")
1337
+ ].some((r) => r.test(e));
1338
+ }
1339
+ /**
1340
+ * Check if a file exists without loading it
1341
+ * @param filePath File path to check
1342
+ * @returns Promise resolving to true if file exists
1343
+ */
1344
+ async exists(e) {
1345
+ const t = this.resolvePath(e);
1346
+ try {
1347
+ return await C.access(t, C.constants.F_OK), !0;
1348
+ } catch {
1349
+ return !1;
1350
+ }
1351
+ }
1352
+ /**
1353
+ * Get file statistics (size, modification time, etc.)
1354
+ * @param filePath File path to check
1355
+ * @returns Promise resolving to file stats
1356
+ */
1357
+ async getStats(e) {
1358
+ const t = this.resolvePath(e);
1359
+ return C.stat(t);
1360
+ }
1361
+ /**
1362
+ * Set a new base directory for resolving relative paths
1363
+ * @param baseDir New base directory
1364
+ */
1365
+ setBaseDir(e) {
1366
+ this.baseDir = e;
1367
+ }
1368
+ /**
1369
+ * Get the current base directory
1370
+ * @returns Current base directory
1371
+ */
1372
+ getBaseDir() {
1373
+ return this.baseDir;
1374
+ }
1375
+ /**
1376
+ * List all files in a directory
1377
+ * @param dirPath Directory path to list
1378
+ * @param recursive Whether to recursively list subdirectories (default: false)
1379
+ * @returns Promise resolving to array of file paths
1380
+ */
1381
+ async listDirectory(e, t = !1) {
1382
+ const r = this.resolvePath(e), s = await C.readdir(r, { withFileTypes: !0 }), i = [];
1383
+ for (const o of s) {
1384
+ const n = T.join(r, o.name);
1385
+ if (o.isDirectory() && t) {
1386
+ const a = await this.listDirectory(n, !0);
1387
+ i.push(...a);
1388
+ } else o.isFile() && i.push(n);
1389
+ }
1390
+ return i;
1391
+ }
1392
+ }
1393
+ const te = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1394
+ __proto__: null,
1395
+ NodeResourceLoader: ee
1396
+ }, Symbol.toStringTag, { value: "Module" }));
1397
+ var I = /* @__PURE__ */ ((c) => (c.BROWSER = "browser", c.NODE = "node", c.UNKNOWN = "unknown", c))(I || {});
1398
+ class N {
1399
+ /**
1400
+ * Detect the current runtime environment
1401
+ * @returns The detected environment type
1402
+ */
1403
+ static detectEnvironment() {
1404
+ return typeof window < "u" && typeof window.document < "u" && typeof fetch < "u" ? "browser" : typeof process < "u" && process.versions != null && process.versions.node != null ? "node" : "unknown";
1405
+ }
1406
+ /**
1407
+ * Check if the current environment is a browser
1408
+ * @returns true if running in a browser
1409
+ */
1410
+ static isBrowser() {
1411
+ return this.detectEnvironment() === "browser";
1412
+ }
1413
+ /**
1414
+ * Check if the current environment is Node.js
1415
+ * @returns true if running in Node.js
1416
+ */
1417
+ static isNode() {
1418
+ return this.detectEnvironment() === "node";
1419
+ }
1420
+ /**
1421
+ * Create a resource loader for the current environment
1422
+ * @param options Optional factory configuration
1423
+ * @returns A resource loader instance appropriate for the current platform
1424
+ * @throws Error if the environment is not supported
1425
+ */
1426
+ static async create(e) {
1427
+ const t = e?.forceEnvironment || this.detectEnvironment();
1428
+ switch (t) {
1429
+ case "browser":
1430
+ return await this.createBrowserLoader(e);
1431
+ case "node":
1432
+ return await this.createNodeLoader(e);
1433
+ case "unknown":
1434
+ throw new Error(
1435
+ "Unsupported environment: Unable to determine runtime environment. Please specify forceEnvironment in options."
1436
+ );
1437
+ default:
1438
+ throw new Error(`Unsupported environment: ${t}`);
1439
+ }
1440
+ }
1441
+ /**
1442
+ * Create a browser resource loader
1443
+ * @param options Optional factory configuration
1444
+ * @returns A browser resource loader instance
1445
+ */
1446
+ static async createBrowserLoader(e) {
1447
+ const { BrowserResourceLoader: t } = await Promise.resolve().then(() => Z);
1448
+ return new t(e?.baseUrl, e?.timeout);
1449
+ }
1450
+ /**
1451
+ * Create a Node.js resource loader
1452
+ * @param options Optional factory configuration
1453
+ * @returns A Node.js resource loader instance
1454
+ */
1455
+ static async createNodeLoader(e) {
1456
+ const { NodeResourceLoader: t } = await Promise.resolve().then(() => te);
1457
+ return new t(e?.baseDir);
1458
+ }
1459
+ /**
1460
+ * Create a resource loader with automatic fallback
1461
+ * If the preferred loader is not available, falls back to the available loader
1462
+ * @param preferredEnvironment Preferred environment
1463
+ * @param options Optional factory configuration
1464
+ * @returns A resource loader instance
1465
+ */
1466
+ static async createWithFallback(e, t) {
1467
+ try {
1468
+ return t = { ...t, forceEnvironment: e }, await this.create(t);
1469
+ } catch {
1470
+ return await this.create({ ...t, forceEnvironment: void 0 });
1471
+ }
1472
+ }
1473
+ }
1474
+ async function re(c) {
1475
+ return await N.create(c);
1476
+ }
1477
+ const se = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1478
+ __proto__: null,
1479
+ Environment: I,
1480
+ ResourceLoaderFactory: N,
1481
+ createResourceLoader: re
1482
+ }, Symbol.toStringTag, { value: "Module" }));
1483
+ class ie {
1484
+ constructor(e = !0) {
1485
+ this.cache = /* @__PURE__ */ new Map(), this.enabled = e;
1486
+ }
1487
+ get(e) {
1488
+ if (this.enabled)
1489
+ return this.cache.get(e);
1490
+ }
1491
+ set(e, t) {
1492
+ this.enabled && this.cache.set(e, t);
1493
+ }
1494
+ has(e) {
1495
+ return this.enabled ? this.cache.has(e) : !1;
1496
+ }
1497
+ clear() {
1498
+ this.cache.clear();
1499
+ }
1500
+ size() {
1501
+ return this.cache.size;
1502
+ }
1503
+ enable() {
1504
+ this.enabled = !0;
1505
+ }
1506
+ disable() {
1507
+ this.enabled = !1;
1508
+ }
1509
+ }
1510
+ class oe {
1511
+ /**
1512
+ * Create a new resource loading pipeline
1513
+ * @param loader Resource loader instance
1514
+ * @param options Pipeline configuration options
1515
+ */
1516
+ constructor(e, t) {
1517
+ this.loader = e, this.concurrency = t?.concurrency ?? 10, this.cache = new ie(t?.cache ?? !0);
1518
+ }
1519
+ /**
1520
+ * Load a single resource with caching support
1521
+ * @param path Resource path or URL
1522
+ * @param options Optional loading options
1523
+ * @returns Promise resolving to the resource content
1524
+ */
1525
+ async load(e, t) {
1526
+ const r = this.cache.get(e);
1527
+ if (r !== void 0)
1528
+ return r;
1529
+ const s = await this.loader.load(e, t);
1530
+ return this.cache.set(e, s), s;
1531
+ }
1532
+ /**
1533
+ * Load multiple resources with concurrency control
1534
+ * @param paths Array of resource paths
1535
+ * @param options Optional loading options
1536
+ * @returns Promise resolving to batch load result
1537
+ */
1538
+ async loadBatch(e, t) {
1539
+ const r = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map();
1540
+ for (let i = 0; i < e.length; i += this.concurrency) {
1541
+ const o = e.slice(i, i + this.concurrency), n = await this.loader.loadMultiple(o, t);
1542
+ for (const a of n)
1543
+ a.success ? (r.set(a.path, a.data), this.cache.set(a.path, a.data)) : s.set(a.path, a.error || "Unknown error");
1544
+ }
1545
+ return {
1546
+ succeeded: r,
1547
+ failed: s,
1548
+ total: e.length,
1549
+ successCount: r.size,
1550
+ failureCount: s.size
1551
+ };
1552
+ }
1553
+ /**
1554
+ * Load a shader from separate vertex and fragment files
1555
+ * @param vertexPath Path to vertex shader file
1556
+ * @param fragmentPath Path to fragment shader file
1557
+ * @param options Optional loading options
1558
+ * @returns Promise resolving to shader source code
1559
+ */
1560
+ async loadShader(e, t, r) {
1561
+ const [s, i] = await Promise.all([
1562
+ this.load(e, r),
1563
+ this.load(t, r)
1564
+ ]);
1565
+ return { vertex: s, fragment: i };
1566
+ }
1567
+ /**
1568
+ * Load multiple shaders
1569
+ * @param shaders Array of shader definitions
1570
+ * @param options Optional loading options
1571
+ * @returns Promise resolving to array of named shader sources
1572
+ */
1573
+ async loadShaders(e, t) {
1574
+ return await Promise.all(
1575
+ e.map(async (s) => {
1576
+ const i = await this.loadShader(
1577
+ s.vertex,
1578
+ s.fragment,
1579
+ t
1580
+ );
1581
+ return {
1582
+ name: s.name,
1583
+ ...i
1584
+ };
1585
+ })
1586
+ );
1587
+ }
1588
+ /**
1589
+ * Load resources from a manifest file
1590
+ * @param manifestPath Path to JSON manifest file
1591
+ * @param options Optional loading options
1592
+ * @returns Promise resolving to batch load result
1593
+ */
1594
+ async loadFromManifest(e, t) {
1595
+ const r = await this.load(e, t), s = JSON.parse(r);
1596
+ return this.loadBatch(s.resources, t);
1597
+ }
1598
+ /**
1599
+ * Preload resources for faster access later
1600
+ * @param paths Array of resource paths to preload
1601
+ * @param options Optional loading options
1602
+ * @returns Promise resolving when all resources are loaded
1603
+ */
1604
+ async preload(e, t) {
1605
+ await this.loadBatch(e, t);
1606
+ }
1607
+ /**
1608
+ * Check if a resource is cached
1609
+ * @param path Resource path
1610
+ * @returns true if the resource is in the cache
1611
+ */
1612
+ isCached(e) {
1613
+ return this.cache.has(e);
1614
+ }
1615
+ /**
1616
+ * Get a resource from cache without loading
1617
+ * @param path Resource path
1618
+ * @returns Cached content or undefined if not cached
1619
+ */
1620
+ getCached(e) {
1621
+ return this.cache.get(e);
1622
+ }
1623
+ /**
1624
+ * Clear the resource cache
1625
+ */
1626
+ clearCache() {
1627
+ this.cache.clear();
1628
+ }
1629
+ /**
1630
+ * Get cache statistics
1631
+ * @returns Number of cached resources
1632
+ */
1633
+ getCacheSize() {
1634
+ return this.cache.size();
1635
+ }
1636
+ /**
1637
+ * Enable caching
1638
+ */
1639
+ enableCache() {
1640
+ this.cache.enable();
1641
+ }
1642
+ /**
1643
+ * Disable caching
1644
+ */
1645
+ disableCache() {
1646
+ this.cache.disable();
1647
+ }
1648
+ /**
1649
+ * Set the maximum concurrency for batch operations
1650
+ * @param concurrency Maximum concurrent loads
1651
+ */
1652
+ setConcurrency(e) {
1653
+ this.concurrency = Math.max(1, e);
1654
+ }
1655
+ /**
1656
+ * Get the underlying resource loader
1657
+ * @returns The resource loader instance
1658
+ */
1659
+ getLoader() {
1660
+ return this.loader;
1661
+ }
1662
+ }
1663
+ async function ne(c) {
1664
+ const { ResourceLoaderFactory: e } = await Promise.resolve().then(() => se), t = await e.create({
1665
+ baseUrl: c?.baseUrl,
1666
+ baseDir: c?.baseDir,
1667
+ timeout: c?.timeout
1668
+ });
1669
+ return new oe(t, c);
1670
+ }
1671
+ const L = {
1672
+ width: 800,
1673
+ height: 600
1674
+ }, P = {
1675
+ quad: {
1676
+ vertices: new Float32Array([
1677
+ // Position TexCoord
1678
+ -0.5,
1679
+ -0.5,
1680
+ 0,
1681
+ 0,
1682
+ 0,
1683
+ // Bottom-left
1684
+ 0.5,
1685
+ -0.5,
1686
+ 0,
1687
+ 1,
1688
+ 0,
1689
+ // Bottom-right
1690
+ 0.5,
1691
+ 0.5,
1692
+ 0,
1693
+ 1,
1694
+ 1,
1695
+ // Top-right
1696
+ 0.5,
1697
+ 0.5,
1698
+ 0,
1699
+ 1,
1700
+ 1,
1701
+ // Top-right
1702
+ -0.5,
1703
+ 0.5,
1704
+ 0,
1705
+ 0,
1706
+ 1,
1707
+ // Top-left
1708
+ -0.5,
1709
+ -0.5,
1710
+ 0,
1711
+ 0,
1712
+ 0
1713
+ // Bottom-left
1714
+ ]),
1715
+ stride: 20
1716
+ // 5 floats per vertex × 4 bytes
1717
+ }
1718
+ }, S = {
1719
+ size: 256
1720
+ }, M = {
1721
+ shaders: [
1722
+ {
1723
+ name: "basic",
1724
+ vertex: "resources/shaders/basic.vert",
1725
+ fragment: "resources/shaders/basic.frag"
1726
+ },
1727
+ {
1728
+ name: "glow",
1729
+ vertex: "resources/shaders/glow.vert",
1730
+ fragment: "resources/shaders/glow.frag"
1731
+ }
1732
+ ],
1733
+ // Additional resources to demonstrate batch loading
1734
+ resources: [
1735
+ "resources/shaders/basic.vert",
1736
+ "resources/shaders/basic.frag",
1737
+ "resources/shaders/glow.vert",
1738
+ "resources/shaders/glow.frag"
1739
+ ]
1740
+ };
1741
+ async function ae() {
1742
+ console.log("🩸 Bloody Engine - Resource Loader Demo"), console.log(`==========================================
1743
+ `);
1744
+ const c = N.detectEnvironment();
1745
+ if (console.log(`✓ Environment detected: ${c}`), c !== I.BROWSER) {
1746
+ console.warn("⚠ This demo is designed for browser environment");
1747
+ return;
1748
+ }
1749
+ console.log(`
1750
+ 1. Creating Resource Pipeline...`);
1751
+ const e = await ne({
1752
+ concurrency: 5,
1753
+ cache: !0,
1754
+ timeout: 1e4,
1755
+ baseUrl: window.location.origin
1756
+ });
1757
+ console.log("✓ Resource pipeline created"), console.log(" - Concurrency: 5"), console.log(" - Caching: enabled"), console.log(`
1758
+ 2. Batch Loading Resources...`), console.log(`Loading ${M.resources.length} resources...`);
1759
+ const t = await e.loadBatch(M.resources);
1760
+ if (console.log("✓ Batch loading complete"), console.log(` - Succeeded: ${t.successCount}`), console.log(` - Failed: ${t.failureCount}`), t.failureCount > 0) {
1761
+ console.log(`
1762
+ ❌ Failed resources:`);
1763
+ for (const [g, p] of t.failed)
1764
+ console.log(` - ${g}: ${p}`);
1765
+ console.log(`
1766
+ ⚠️ Falling back to inline shaders...`);
1767
+ }
1768
+ console.log(`
1769
+ 3. Loading Shaders...`);
1770
+ const r = await e.loadShaders(M.shaders);
1771
+ console.log(`✓ Loaded ${r.length} shaders:`);
1772
+ for (const g of r)
1773
+ console.log(` - ${g.name}:`), console.log(` Vertex: ${g.vertex.length} chars`), console.log(` Fragment: ${g.fragment.length} chars`);
1774
+ console.log(`
1775
+ 4. Testing Cache...`);
1776
+ const s = e.getCacheSize();
1777
+ console.log(`✓ Cache contains ${s} resources`);
1778
+ for (const g of M.shaders) {
1779
+ const p = e.isCached(g.vertex), $ = e.isCached(g.fragment);
1780
+ console.log(` - ${g.name}:`), console.log(` Vertex cached: ${p}`), console.log(` Fragment cached: ${$}`);
1781
+ }
1782
+ console.log(`
1783
+ 5. Initializing Graphics Device...`);
1784
+ const i = new W(L.width, L.height), o = i.getGLContext();
1785
+ console.log("✓ Graphics device initialized"), console.log(` - Resolution: ${L.width}x${L.height}`), console.log(`
1786
+ 6. Creating Shader from Loaded Source...`);
1787
+ let n = r.find((g) => g.name === "glow");
1788
+ (!n || !n.vertex || !n.fragment) && (console.warn("⚠️ Glow shader not loaded or empty, using inline fallback"), n = {
1789
+ name: "glow",
1790
+ vertex: `attribute vec3 aPosition;
1791
+ attribute vec2 aTexCoord;
1792
+
1793
+ varying vec2 vTexCoord;
1794
+ varying float vDistance;
1795
+
1796
+ uniform mat4 uMatrix;
1797
+
1798
+ void main() {
1799
+ gl_Position = uMatrix * vec4(aPosition, 1.0);
1800
+ vTexCoord = aTexCoord;
1801
+ vDistance = length(aTexCoord - vec2(0.5, 0.5));
1802
+ }`,
1803
+ fragment: `precision mediump float;
1804
+
1805
+ varying vec2 vTexCoord;
1806
+ varying float vDistance;
1807
+ uniform sampler2D uTexture;
1808
+ uniform vec3 uColor;
1809
+ uniform float uGlowIntensity;
1810
+
1811
+ void main() {
1812
+ vec4 texColor = texture2D(uTexture, vTexCoord);
1813
+ // Better glow falloff - keeps minimum brightness
1814
+ float glow = 1.0 - (vDistance * 0.7);
1815
+ glow = max(0.5, glow);
1816
+ vec3 glowColor = texColor.rgb * uColor * glow * uGlowIntensity;
1817
+ gl_FragColor = vec4(glowColor, texColor.a);
1818
+ }`
1819
+ });
1820
+ const a = i.createShader(n.vertex, n.fragment);
1821
+ console.log("✓ Shader compiled from loaded source code"), console.log(" - Vertex shader: compiled"), console.log(" - Fragment shader: compiled"), console.log(" - Program: linked"), console.log(`
1822
+ 7. Creating Texture...`);
1823
+ const h = B.createGradient(
1824
+ o,
1825
+ S.size,
1826
+ S.size
1827
+ );
1828
+ console.log("✓ Gradient texture created"), console.log(` - Size: ${S.size}x${S.size}`), console.log(`
1829
+ 8. Creating Geometry Buffers...`);
1830
+ const { VertexBuffer: x } = await Promise.resolve().then(() => K), l = new x(
1831
+ o,
1832
+ P.quad.vertices,
1833
+ P.quad.stride
1834
+ );
1835
+ console.log("✓ Quad buffer created"), console.log(` - Vertices: ${l.getVertexCount()}`), console.log(`
1836
+ 9. Setting up Rendering...`), a.use();
1837
+ const d = a.getAttributeLocation("aPosition"), f = a.getAttributeLocation("aTexCoord"), y = a.getUniformLocation("uTexture"), m = a.getUniformLocation("uMatrix"), v = a.getUniformLocation("uColor"), E = a.getUniformLocation("uGlowIntensity");
1838
+ l.bind(), o.enableVertexAttribArray(d), o.vertexAttribPointer(d, 3, o.FLOAT, !1, P.quad.stride, 0), o.enableVertexAttribArray(f), o.vertexAttribPointer(
1839
+ f,
1840
+ 2,
1841
+ o.FLOAT,
1842
+ !1,
1843
+ P.quad.stride,
1844
+ 12
1845
+ ), console.log("✓ Vertex attributes configured"), h.bind(0), o.uniform1i(y, 0), console.log("✓ Texture bound to unit 0");
1846
+ const u = i.getRenderingContext().canvas;
1847
+ u && (u.style.display = "block", u.style.margin = "0 auto", u.style.border = "2px solid #333", u.style.backgroundColor = "#1a1a1a"), document.body.style.margin = "0", document.body.style.padding = "20px", document.body.style.backgroundColor = "#0a0a0a", document.body.style.fontFamily = "monospace", document.body.style.color = "#aaa";
1848
+ const w = document.createElement("h1");
1849
+ w.textContent = "🩸 Resource Loader Demo", w.style.textAlign = "center", w.style.color = "#fff", u && u.parentNode ? u.parentNode.insertBefore(w, u) : document.body.insertBefore(w, document.body.firstChild);
1850
+ const b = document.createElement("div");
1851
+ b.style.textAlign = "center", b.style.marginTop = "10px", b.style.fontSize = "12px", b.innerHTML = `
1852
+ <div>Environment: <strong>${c}</strong></div>
1853
+ <div>Shaders loaded: <strong>${r.length}</strong></div>
1854
+ <div>Cached resources: <strong>${s}</strong></div>
1855
+ `, document.body.appendChild(b);
1856
+ let _ = 0;
1857
+ const D = Date.now();
1858
+ function U() {
1859
+ const g = Date.now(), p = (g - D) / 1e3;
1860
+ i.clear({ r: 0.1, g: 0.1, b: 0.1, a: 1 });
1861
+ const $ = [
1862
+ { x: -0.3, y: 0.3, color: [1, 0.2, 0.2], glow: 1.5 },
1863
+ { x: 0.3, y: 0.3, color: [0.2, 1, 0.2], glow: 1.8 },
1864
+ { x: -0.3, y: -0.3, color: [0.2, 0.5, 1], glow: 2 },
1865
+ { x: 0.3, y: -0.3, color: [1, 1, 0.2], glow: 1.6 }
1866
+ ];
1867
+ for (const R of $) {
1868
+ const z = ce();
1869
+ if (he(z, R.x, R.y, 0), le(z, 0.4, 0.4, 1), m && o.uniformMatrix4fv(m, !1, z), v && o.uniform3f(
1870
+ v,
1871
+ R.color[0],
1872
+ R.color[1],
1873
+ R.color[2]
1874
+ ), E) {
1875
+ const q = R.glow + Math.sin(p * 2) * 0.3;
1876
+ o.uniform1f(E, q);
1877
+ }
1878
+ o.drawArrays(o.TRIANGLES, 0, l.getVertexCount());
1879
+ }
1880
+ i.present(), _++;
1881
+ const V = (g - D) / 1e3, O = _ / V;
1882
+ b.innerHTML = `
1883
+ <div>FPS: <strong>${O.toFixed(1)}</strong> | Frame: <strong>${_}</strong> | Elapsed: <strong>${V.toFixed(2)}s</strong></div>
1884
+ <div>Environment: <strong>${c}</strong> | Shaders loaded: <strong>${r.length}</strong> | Cached: <strong>${s}</strong></div>
1885
+ `, requestAnimationFrame(U);
1886
+ }
1887
+ console.log(`
1888
+ ✓ Demo started! Rendering animation...`), U();
1889
+ }
1890
+ function ce() {
1891
+ return new Float32Array([
1892
+ 1,
1893
+ 0,
1894
+ 0,
1895
+ 0,
1896
+ 0,
1897
+ 1,
1898
+ 0,
1899
+ 0,
1900
+ 0,
1901
+ 0,
1902
+ 1,
1903
+ 0,
1904
+ 0,
1905
+ 0,
1906
+ 0,
1907
+ 1
1908
+ ]);
1909
+ }
1910
+ function he(c, e, t, r) {
1911
+ c[12] += e, c[13] += t, c[14] += r;
1912
+ }
1913
+ function le(c, e, t, r) {
1914
+ c[0] *= e, c[5] *= t, c[10] *= r;
1915
+ }
1916
+ typeof window < "u" && ae().catch((c) => {
1917
+ console.error("❌ Demo failed:", c);
1918
+ });
1919
+ export {
1920
+ de as BatchRenderer,
1921
+ Y as BrowserRenderingContext,
1922
+ J as BrowserResourceLoader,
1923
+ ge as Camera,
1924
+ I as Environment,
1925
+ W as GraphicsDevice,
1926
+ j as IndexBuffer,
1927
+ F as Matrix4,
1928
+ G as NodeRenderingContext,
1929
+ ee as NodeResourceLoader,
1930
+ k as RenderingContextFactory,
1931
+ N as ResourceLoaderFactory,
1932
+ oe as ResourcePipeline,
1933
+ H as Shader,
1934
+ fe as SpriteBatchRenderer,
1935
+ B as Texture,
1936
+ Q as VertexBuffer,
1937
+ re as createResourceLoader,
1938
+ ne as createResourcePipeline,
1939
+ ae as runBrowserResourceLoaderDemo
1940
+ };