melonjs 10.6.1 → 10.8.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.
Files changed (79) hide show
  1. package/dist/melonjs.js +37947 -36530
  2. package/dist/melonjs.min.js +22 -22
  3. package/dist/melonjs.module.d.ts +1352 -307
  4. package/dist/melonjs.module.js +2929 -1501
  5. package/package.json +14 -12
  6. package/src/camera/camera2d.js +1 -1
  7. package/src/entity/entity.js +6 -7
  8. package/src/game.js +5 -5
  9. package/src/geometries/ellipse.js +10 -11
  10. package/src/geometries/line.js +3 -3
  11. package/src/geometries/path2d.js +319 -0
  12. package/src/geometries/poly.js +11 -11
  13. package/src/geometries/rectangle.js +30 -15
  14. package/src/geometries/roundrect.js +67 -0
  15. package/src/index.js +9 -5
  16. package/src/input/gamepad.js +12 -10
  17. package/src/input/keyboard.js +5 -3
  18. package/src/input/pointer.js +1 -1
  19. package/src/input/pointerevent.js +3 -4
  20. package/src/lang/deprecated.js +1 -1
  21. package/src/level/tiled/TMXLayer.js +1 -1
  22. package/src/level/tiled/TMXObject.js +9 -12
  23. package/src/level/tiled/TMXTileMap.js +23 -4
  24. package/src/level/tiled/TMXUtils.js +1 -1
  25. package/src/level/tiled/renderer/TMXHexagonalRenderer.js +1 -1
  26. package/src/level/tiled/renderer/TMXIsometricRenderer.js +1 -1
  27. package/src/level/tiled/renderer/TMXOrthogonalRenderer.js +1 -1
  28. package/src/level/tiled/renderer/TMXRenderer.js +1 -1
  29. package/src/level/tiled/renderer/TMXStaggeredRenderer.js +1 -1
  30. package/src/loader/loader.js +5 -5
  31. package/src/loader/loadingscreen.js +1 -1
  32. package/src/math/color.js +1 -1
  33. package/src/math/matrix2.js +1 -1
  34. package/src/math/matrix3.js +67 -66
  35. package/src/math/observable_vector2.js +1 -1
  36. package/src/math/observable_vector3.js +1 -1
  37. package/src/math/vector2.js +1 -1
  38. package/src/math/vector3.js +1 -1
  39. package/src/particles/emitter.js +130 -430
  40. package/src/particles/particle.js +53 -53
  41. package/src/particles/settings.js +310 -0
  42. package/src/physics/body.js +67 -51
  43. package/src/physics/bounds.js +8 -9
  44. package/src/physics/world.js +1 -1
  45. package/src/polyfill/console.js +7 -7
  46. package/src/polyfill/index.js +7 -0
  47. package/src/polyfill/performance.js +20 -0
  48. package/src/polyfill/requestAnimationFrame.js +10 -10
  49. package/src/renderable/collectable.js +9 -2
  50. package/src/renderable/colorlayer.js +1 -1
  51. package/src/renderable/container.js +1 -1
  52. package/src/renderable/imagelayer.js +3 -3
  53. package/src/renderable/renderable.js +1 -1
  54. package/src/renderable/sprite.js +2 -3
  55. package/src/renderable/trigger.js +10 -4
  56. package/src/state/stage.js +1 -1
  57. package/src/state/state.js +8 -8
  58. package/src/system/device.js +148 -133
  59. package/src/system/event.js +10 -10
  60. package/src/system/pooling.js +156 -149
  61. package/src/system/timer.js +1 -1
  62. package/src/text/bitmaptext.js +1 -1
  63. package/src/text/text.js +1 -1
  64. package/src/utils/agent.js +4 -4
  65. package/src/utils/function.js +2 -2
  66. package/src/utils/utils.js +10 -5
  67. package/src/video/canvas/canvas_renderer.js +104 -36
  68. package/src/video/renderer.js +28 -16
  69. package/src/video/texture.js +1 -1
  70. package/src/video/video.js +11 -11
  71. package/src/video/webgl/glshader.js +30 -194
  72. package/src/video/webgl/utils/attributes.js +16 -0
  73. package/src/video/webgl/utils/precision.js +11 -0
  74. package/src/video/webgl/utils/program.js +58 -0
  75. package/src/video/webgl/utils/string.js +16 -0
  76. package/src/video/webgl/utils/uniforms.js +87 -0
  77. package/src/video/webgl/webgl_compositor.js +1 -14
  78. package/src/video/webgl/webgl_renderer.js +129 -186
  79. package/src/particles/particlecontainer.js +0 -95
@@ -54,6 +54,18 @@ class CanvasRenderer extends Renderer {
54
54
  // enable the tile texture seam fix with the canvas renderer
55
55
  this.uvOffset = 1;
56
56
  }
57
+
58
+ // context lost & restore event for canvas
59
+ this.getScreenCanvas().addEventListener("contextlost", (e) => {
60
+ e.preventDefault();
61
+ this.isContextValid = false;
62
+ event.emit(event.ONCONTEXT_LOST, this);
63
+ }, false );
64
+ // ctx.restoreContext()
65
+ this.getScreenCanvas().addEventListener("contextrestored", () => {
66
+ this.isContextValid = true;
67
+ event.emit(event.ONCONTEXT_RESTORED, this);
68
+ }, false );
57
69
  }
58
70
 
59
71
  /**
@@ -84,7 +96,7 @@ class CanvasRenderer extends Renderer {
84
96
  * <img src="images/normal-blendmode.png" width="510"/> <br>
85
97
  * - "multiply" : the pixels of the top layer are multiplied with the corresponding pixel of the bottom layer. A darker picture is the result. <br>
86
98
  * <img src="images/multiply-blendmode.png" width="510"/> <br>
87
- * - "lighter" : where both content overlap the color is determined by adding color values. <br>
99
+ * - "additive or lighter" : where both content overlap the color is determined by adding color values. <br>
88
100
  * <img src="images/lighter-blendmode.png" width="510"/> <br>
89
101
  * - "screen" : The pixels are inverted, multiplied, and inverted again. A lighter picture is the result (opposite of multiply) <br>
90
102
  * <img src="images/screen-blendmode.png" width="510"/> <br>
@@ -92,7 +104,7 @@ class CanvasRenderer extends Renderer {
92
104
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
93
105
  * @memberof CanvasRenderer.prototype
94
106
  * @function
95
- * @param {string} [mode="normal"] blend mode : "normal", "multiply", "lighter, "screen"
107
+ * @param {string} [mode="normal"] blend mode : "normal", "multiply", "lighter, "additive", "screen"
96
108
  * @param {CanvasRenderingContext2D} [context]
97
109
  */
98
110
  setBlendMode(mode = "normal", context) {
@@ -104,6 +116,7 @@ class CanvasRenderer extends Renderer {
104
116
  break;
105
117
 
106
118
  case "lighter" :
119
+ case "additive" :
107
120
  context.globalCompositeOperation = "lighter";
108
121
  break;
109
122
 
@@ -176,7 +189,7 @@ class CanvasRenderer extends Renderer {
176
189
  * @param {number} height The rectangle's height.
177
190
  */
178
191
  clearRect(x, y, width, height) {
179
- this.backBufferContext2D.clearRect(x, y, width, height);
192
+ this.getContext().clearRect(x, y, width, height);
180
193
  }
181
194
 
182
195
  /**
@@ -195,7 +208,7 @@ class CanvasRenderer extends Renderer {
195
208
  * var basic = renderer.createPattern(image, "no-repeat");
196
209
  */
197
210
  createPattern(image, repeat) {
198
- return this.backBufferContext2D.createPattern(image, repeat);
211
+ return this.getContext().createPattern(image, repeat);
199
212
  }
200
213
 
201
214
  /**
@@ -221,10 +234,11 @@ class CanvasRenderer extends Renderer {
221
234
  * renderer.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
222
235
  */
223
236
  drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
224
- if (this.backBufferContext2D.globalAlpha < 1 / 255) {
237
+ if (this.getGlobalAlpha() < 1 / 255) {
225
238
  // Fast path: don't draw fully transparent
226
239
  return;
227
240
  }
241
+ var context = this.getContext();
228
242
 
229
243
  if (typeof sw === "undefined") {
230
244
  sw = dw = image.width;
@@ -258,7 +272,7 @@ class CanvasRenderer extends Renderer {
258
272
  // get a tinted version of this image from the texture cache
259
273
  source = this.cache.tint(image, this.currentTint.toRGB());
260
274
  }
261
- this.backBufferContext2D.drawImage(source, sx, sy, sw, sh, dx, dy, dw, dh);
275
+ context.drawImage(source, sx, sy, sw, sh, dx, dy, dw, dh);
262
276
  }
263
277
 
264
278
  /**
@@ -274,14 +288,15 @@ class CanvasRenderer extends Renderer {
274
288
  * @see CanvasRenderer#createPattern
275
289
  */
276
290
  drawPattern(pattern, x, y, width, height) {
277
- if (this.backBufferContext2D.globalAlpha < 1 / 255) {
291
+ if (this.getGlobalAlpha() < 1 / 255) {
278
292
  // Fast path: don't draw fully transparent
279
293
  return;
280
294
  }
281
- var fillStyle = this.backBufferContext2D.fillStyle;
282
- this.backBufferContext2D.fillStyle = pattern;
283
- this.backBufferContext2D.fillRect(x, y, width, height);
284
- this.backBufferContext2D.fillStyle = fillStyle;
295
+ var context = this.getContext();
296
+ var fillStyle = context.fillStyle;
297
+ context.fillStyle = pattern;
298
+ context.fillRect(x, y, width, height);
299
+ context.fillStyle = fillStyle;
285
300
  }
286
301
 
287
302
  /**
@@ -298,12 +313,12 @@ class CanvasRenderer extends Renderer {
298
313
  * @param {boolean} [fill=false] also fill the shape with the current color if true
299
314
  */
300
315
  strokeArc(x, y, radius, start, end, antiClockwise, fill = false) {
301
- var context = this.backBufferContext2D;
302
-
303
- if (context.globalAlpha < 1 / 255) {
316
+ if (this.getGlobalAlpha() < 1 / 255) {
304
317
  // Fast path: don't draw fully transparent
305
318
  return;
306
319
  }
320
+ var context = this.getContext();
321
+
307
322
  context.translate(x, y);
308
323
  context.beginPath();
309
324
  context.arc(0, 0, radius, start, end, antiClockwise || false);
@@ -339,12 +354,11 @@ class CanvasRenderer extends Renderer {
339
354
  * @param {boolean} [fill=false] also fill the shape with the current color if true
340
355
  */
341
356
  strokeEllipse(x, y, w, h, fill = false) {
342
- var context = this.backBufferContext2D;
343
-
344
- if (context.globalAlpha < 1 / 255) {
357
+ if (this.getGlobalAlpha() < 1 / 255) {
345
358
  // Fast path: don't draw fully transparent
346
359
  return;
347
360
  }
361
+ var context = this.getContext();
348
362
 
349
363
  var hw = w,
350
364
  hh = h,
@@ -395,9 +409,7 @@ class CanvasRenderer extends Renderer {
395
409
  * @param {number} endY the end y coordinate
396
410
  */
397
411
  strokeLine(startX, startY, endX, endY) {
398
- var context = this.backBufferContext2D;
399
-
400
- if (context < 1 / 255) {
412
+ if (this.getGlobalAlpha() < 1 / 255) {
401
413
  // Fast path: don't draw fully transparent
402
414
  return;
403
415
  }
@@ -431,12 +443,11 @@ class CanvasRenderer extends Renderer {
431
443
  * @param {boolean} [fill=false] also fill the shape with the current color if true
432
444
  */
433
445
  strokePolygon(poly, fill = false) {
434
- var context = this.backBufferContext2D;
435
-
436
- if (context.globalAlpha < 1 / 255) {
446
+ if (this.getGlobalAlpha() < 1 / 255) {
437
447
  // Fast path: don't draw fully transparent
438
448
  return;
439
449
  }
450
+ var context = this.getContext();
440
451
 
441
452
  this.translate(poly.pos.x, poly.pos.y);
442
453
  context.beginPath();
@@ -475,15 +486,13 @@ class CanvasRenderer extends Renderer {
475
486
  * @param {boolean} [fill=false] also fill the shape with the current color if true
476
487
  */
477
488
  strokeRect(x, y, width, height, fill = false) {
478
- if (fill === true ) {
479
- this.fillRect(x, y, width, height);
480
- } else {
481
- if (this.backBufferContext2D.globalAlpha < 1 / 255) {
482
- // Fast path: don't draw fully transparent
483
- return;
484
- }
485
- this.backBufferContext2D.strokeRect(x, y, width, height);
489
+ if (this.getGlobalAlpha() < 1 / 255) {
490
+ // Fast path: don't draw fully transparent
491
+ return;
486
492
  }
493
+ var context = this.getContext();
494
+
495
+ context[fill === true ? "fillRect" : "strokeRect"](x, y, width, height);
487
496
  }
488
497
 
489
498
  /**
@@ -497,11 +506,59 @@ class CanvasRenderer extends Renderer {
497
506
  * @param {number} height
498
507
  */
499
508
  fillRect(x, y, width, height) {
500
- if (this.backBufferContext2D.globalAlpha < 1 / 255) {
509
+ this.strokeRect(x, y, width, height, true);
510
+ }
511
+
512
+ /**
513
+ * Stroke a rounded rectangle at the specified coordinates
514
+ * @name strokeRoundRect
515
+ * @memberof CanvasRenderer.prototype
516
+ * @function
517
+ * @param {number} x
518
+ * @param {number} y
519
+ * @param {number} width
520
+ * @param {number} height
521
+ * @param {number} radius
522
+ * @param {boolean} [fill=false] also fill the shape with the current color if true
523
+ */
524
+ strokeRoundRect(x, y, width, height, radius, fill = false) {
525
+ if (this.getGlobalAlpha() < 1 / 255) {
501
526
  // Fast path: don't draw fully transparent
502
527
  return;
503
528
  }
504
- this.backBufferContext2D.fillRect(x, y, width, height);
529
+ var context = this.getContext();
530
+
531
+ context.beginPath();
532
+ if (typeof context.roundRect === "function") {
533
+ //https://developer.chrome.com/blog/canvas2d/#round-rect
534
+ context.roundRect(x, y, width, height, radius);
535
+ } else {
536
+ context.moveTo(x + radius, y);
537
+ context.lineTo(x + width - radius, y);
538
+ context.arcTo(x + width, y, x + width, y + radius, radius);
539
+ context.lineTo(x + width, y + height - radius);
540
+ context.arcTo(x + width, y + height, x + width - radius, y + height, radius);
541
+ context.lineTo(x + radius, y + height);
542
+ context.arcTo(x, y + height, x, y + height - radius, radius);
543
+ context.lineTo(x, y + radius);
544
+ context.arcTo(x, y, x + radius, y, radius);
545
+ }
546
+ context[fill === true ? "fill" : "stroke"]();
547
+ }
548
+
549
+ /**
550
+ * Draw a rounded filled rectangle at the specified coordinates
551
+ * @name fillRoundRect
552
+ * @memberof CanvasRenderer.prototype
553
+ * @function
554
+ * @param {number} x
555
+ * @param {number} y
556
+ * @param {number} width
557
+ * @param {number} height
558
+ * @param {number} radius
559
+ */
560
+ fillRoundRect(x, y, width, height, radius) {
561
+ this.strokeRoundRect(x, y, width, height, radius, true);
505
562
  }
506
563
 
507
564
 
@@ -543,7 +600,7 @@ class CanvasRenderer extends Renderer {
543
600
  */
544
601
  restore() {
545
602
  this.backBufferContext2D.restore();
546
- this.currentColor.glArray[3] = this.backBufferContext2D.globalAlpha;
603
+ this.currentColor.glArray[3] = this.getGlobalAlpha();
547
604
  this.currentScissor[0] = 0;
548
605
  this.currentScissor[1] = 0;
549
606
  this.currentScissor[2] = this.backBufferCanvas.width;
@@ -591,7 +648,7 @@ class CanvasRenderer extends Renderer {
591
648
  }
592
649
 
593
650
  /**
594
- * Set the global alpha on the canvas context
651
+ * Set the global alpha
595
652
  * @name setGlobalAlpha
596
653
  * @memberof CanvasRenderer.prototype
597
654
  * @function
@@ -601,6 +658,17 @@ class CanvasRenderer extends Renderer {
601
658
  this.backBufferContext2D.globalAlpha = this.currentColor.glArray[3] = alpha;
602
659
  }
603
660
 
661
+ /**
662
+ * Return the global alpha
663
+ * @name getGlobalAlpha
664
+ * @memberof CanvasRenderer.prototype
665
+ * @function
666
+ * @returns {number} global alpha value
667
+ */
668
+ getGlobalAlpha() {
669
+ return this.backBufferContext2D.globalAlpha;
670
+ }
671
+
604
672
  /**
605
673
  * Set the line width on the context
606
674
  * @name setLineWidth
@@ -710,7 +778,7 @@ class CanvasRenderer extends Renderer {
710
778
  * @param {Rect|Polygon|Line|Ellipse} [mask] the shape defining the mask to be applied
711
779
  */
712
780
  setMask(mask) {
713
- var context = this.backBufferContext2D;
781
+ var context = this.getContext();
714
782
  var _x = mask.pos.x, _y = mask.pos.y;
715
783
 
716
784
  context.save();
@@ -5,10 +5,12 @@ import * as event from "./../system/event.js";
5
5
  import device from "./../system/device.js";
6
6
  import { setPrefixed } from "./../utils/agent.js";
7
7
  import Rect from "./../geometries/rectangle.js";
8
+ import RoundRect from "./../geometries/roundrect.js";
8
9
  import Ellipse from "./../geometries/ellipse.js";
9
10
  import Polygon from "./../geometries/poly.js";
10
11
  import Line from "./../geometries/line.js";
11
12
  import Bounds from "./../physics/bounds.js";
13
+ import Path2D from "./../geometries/path2d.js";
12
14
 
13
15
  /**
14
16
  * @classdesc
@@ -43,12 +45,20 @@ class Renderer {
43
45
  /**
44
46
  * true if the current rendering context is valid
45
47
  * @name isContextValid
46
- * @memberof Renderer
48
+ * @memberof Renderer#
47
49
  * @default true
48
50
  * type {boolean}
49
51
  */
50
52
  this.isContextValid = true;
51
53
 
54
+ /**
55
+ * The Path2D instance used by the renderer to draw primitives
56
+ * @name path2D
57
+ * @type {Path2D}
58
+ * @memberof Renderer#
59
+ */
60
+ this.path2D = new Path2D();
61
+
52
62
  /**
53
63
  * @ignore
54
64
  */
@@ -63,9 +73,9 @@ class Renderer {
63
73
  if (device.ejecta === true) {
64
74
  // a main canvas is already automatically created by Ejecta
65
75
  this.canvas = document.getElementById("canvas");
66
- } else if (typeof window.canvas !== "undefined") {
76
+ } else if (typeof globalThis.canvas !== "undefined") {
67
77
  // a global canvas is available, e.g. webapp adapter for wechat
68
- this.canvas = window.canvas;
78
+ this.canvas = globalThis.canvas;
69
79
  } else if (typeof this.settings.canvas !== "undefined") {
70
80
  this.canvas = this.settings.canvas;
71
81
  } else {
@@ -331,11 +341,13 @@ class Renderer {
331
341
  * @name stroke
332
342
  * @memberof Renderer.prototype
333
343
  * @function
334
- * @param {Rect|Polygon|Line|Ellipse} shape a shape object to stroke
344
+ * @param {Rect|RoundRect|Polygon|Line|Ellipse} shape a shape object to stroke
335
345
  * @param {boolean} [fill=false] fill the shape with the current color if true
336
346
  */
337
347
  stroke(shape, fill) {
338
- if (shape instanceof Rect || shape instanceof Bounds) {
348
+ if (shape instanceof RoundRect) {
349
+ this.strokeRoundRect(shape.left, shape.top, shape.width, shape.height, shape.radius, fill);
350
+ } else if (shape instanceof Rect || shape instanceof Bounds) {
339
351
  this.strokeRect(shape.left, shape.top, shape.width, shape.height, fill);
340
352
  } else if (shape instanceof Line || shape instanceof Polygon) {
341
353
  this.strokePolygon(shape, fill);
@@ -350,6 +362,17 @@ class Renderer {
350
362
  }
351
363
  }
352
364
 
365
+ /**
366
+ * fill the given shape
367
+ * @name fill
368
+ * @memberof Renderer.prototype
369
+ * @function
370
+ * @param {Rect|Polygon|Line|Ellipse} shape a shape object to fill
371
+ */
372
+ fill(shape) {
373
+ this.stroke(shape, true);
374
+ }
375
+
353
376
  /**
354
377
  * tint the given image or canvas using the given color
355
378
  * @name tint
@@ -379,17 +402,6 @@ class Renderer {
379
402
  return canvas;
380
403
  }
381
404
 
382
- /**
383
- * fill the given shape
384
- * @name fill
385
- * @memberof Renderer.prototype
386
- * @function
387
- * @param {Rect|Polygon|Line|Ellipse} shape a shape object to fill
388
- */
389
- fill(shape) {
390
- this.stroke(shape, true);
391
- }
392
-
393
405
  /**
394
406
  * A mask limits rendering elements to the shape and position of the given mask object.
395
407
  * So, if the renderable is larger than the mask, only the intersecting part of the renderable will be visible.
@@ -3,7 +3,7 @@ import WebGLRenderer from "./webgl/webgl_renderer.js";
3
3
  import TextureCache from "./texture_cache.js";
4
4
  import Sprite from "./../renderable/sprite.js";
5
5
  import { renderer } from "./video.js";
6
- import * as pool from "./../system/pooling.js";
6
+ import pool from "./../system/pooling.js";
7
7
  import loader from "./../loader/loader.js";
8
8
  import { ETA } from "./../math/math.js";
9
9
 
@@ -18,7 +18,7 @@ var designHeight = 0;
18
18
 
19
19
  // default video settings
20
20
  var settings = {
21
- parent : document.body,
21
+ parent : undefined,
22
22
  renderer : 2, // AUTO
23
23
  doubleBuffering : false,
24
24
  autoScale : false,
@@ -64,8 +64,8 @@ function onresize() {
64
64
  var canvasMaxWidth = Infinity;
65
65
  var canvasMaxHeight = Infinity;
66
66
 
67
- if (window.getComputedStyle) {
68
- var style = window.getComputedStyle(renderer.getScreenCanvas(), null);
67
+ if (globalThis.getComputedStyle) {
68
+ var style = globalThis.getComputedStyle(renderer.getScreenCanvas(), null);
69
69
  canvasMaxWidth = parseInt(style.maxWidth, 10) || Infinity;
70
70
  canvasMaxHeight = parseInt(style.maxHeight, 10) || Infinity;
71
71
  }
@@ -276,7 +276,7 @@ export function init(width, height, options) {
276
276
  settings.zoomY = height * scaleRatio.y;
277
277
 
278
278
  //add a channel for the onresize/onorientationchange event
279
- window.addEventListener(
279
+ globalThis.addEventListener(
280
280
  "resize",
281
281
  utils.function.throttle(
282
282
  function (e) {
@@ -286,7 +286,7 @@ export function init(width, height, options) {
286
286
  );
287
287
 
288
288
  // Screen Orientation API
289
- window.addEventListener(
289
+ globalThis.addEventListener(
290
290
  "orientationchange",
291
291
  function (e) {
292
292
  event.emit(event.WINDOW_ONORIENTATION_CHANGE, e);
@@ -294,7 +294,7 @@ export function init(width, height, options) {
294
294
  false
295
295
  );
296
296
  // pre-fixed implementation on mozzila
297
- window.addEventListener(
297
+ globalThis.addEventListener(
298
298
  "onmozorientationchange",
299
299
  function (e) {
300
300
  event.emit(event.WINDOW_ONORIENTATION_CHANGE, e);
@@ -303,13 +303,13 @@ export function init(width, height, options) {
303
303
  );
304
304
 
305
305
  if (device.ScreenOrientation === true) {
306
- window.screen.orientation.onchange = function (e) {
306
+ globalThis.screen.orientation.onchange = function (e) {
307
307
  event.emit(event.WINDOW_ONORIENTATION_CHANGE, e);
308
308
  };
309
309
  }
310
310
 
311
311
  // Automatically update relative canvas position on scroll
312
- window.addEventListener("scroll", utils.function.throttle(
312
+ globalThis.addEventListener("scroll", utils.function.throttle(
313
313
  function (e) {
314
314
  event.emit(event.WINDOW_ONSCROLL, e);
315
315
  }, 100
@@ -336,14 +336,14 @@ export function init(width, height, options) {
336
336
  }
337
337
 
338
338
  // add our canvas (default to document.body if settings.parent is undefined)
339
- parent = device.getElement(settings.parent);
339
+ parent = device.getElement(typeof settings.parent !== "undefined" ? settings.parent : document.body);
340
340
  parent.appendChild(renderer.getScreenCanvas());
341
341
 
342
342
  // trigger an initial resize();
343
343
  onresize();
344
344
 
345
345
  // add an observer to detect when the dom tree is modified
346
- if ("MutationObserver" in window) {
346
+ if ("MutationObserver" in globalThis) {
347
347
  // Create an observer instance linked to the callback function
348
348
  var observer = new MutationObserver(onresize.bind(this));
349
349
 
@@ -362,7 +362,7 @@ export function init(width, height, options) {
362
362
  renderType + " renderer" + gpu_renderer + " | " +
363
363
  audioType + " | " +
364
364
  "pixel ratio " + device.devicePixelRatio + " | " +
365
- (device.isMobile ? "mobile" : "desktop") + " | " +
365
+ (device.nodeJS ? "node.js" : device.isMobile ? "mobile" : "desktop") + " | " +
366
366
  device.getScreenOrientation() + " | " +
367
367
  device.language
368
368
  );