littlejsengine 1.10.4 → 1.10.7

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 (63) hide show
  1. package/README.md +8 -78
  2. package/dist/littlejs.d.ts +31 -17
  3. package/dist/littlejs.esm.js +121 -55
  4. package/dist/littlejs.esm.min.js +1 -1
  5. package/dist/littlejs.js +121 -55
  6. package/dist/littlejs.min.js +1 -1
  7. package/dist/littlejs.release.js +121 -55
  8. package/examples/box2d/game.js +15 -4
  9. package/examples/box2d/gameObjects.js +10 -9
  10. package/examples/box2d/index.html +5 -5
  11. package/examples/box2d/scenes.js +4 -4
  12. package/examples/box2d/tiles.png +0 -0
  13. package/examples/breakout/index.html +3 -3
  14. package/examples/breakoutTutorial/index.html +2 -2
  15. package/examples/electron/game.js +3 -0
  16. package/examples/electron/index.html +2 -2
  17. package/examples/htmlMenu/index.html +3 -3
  18. package/examples/js13k/game.js +3 -0
  19. package/examples/js13k/index.html +13 -13
  20. package/examples/module/game.js +3 -0
  21. package/examples/module/index.html +1 -1
  22. package/examples/particles/index.html +4 -1
  23. package/examples/platformer/game.js +19 -15
  24. package/examples/platformer/gameCharacter.js +3 -3
  25. package/examples/platformer/gameLevel.js +1 -0
  26. package/examples/platformer/index.html +8 -8
  27. package/examples/platformer/tiles.png +0 -0
  28. package/examples/puzzle/index.html +2 -2
  29. package/examples/starter/game.js +3 -0
  30. package/examples/starter/index.html +13 -13
  31. package/examples/stress/index.html +1 -1
  32. package/examples/typescript/game.js +2 -0
  33. package/examples/typescript/game.ts +3 -0
  34. package/examples/typescript/index.html +1 -1
  35. package/examples/uiSystem/game.js +23 -16
  36. package/examples/uiSystem/index.html +3 -14
  37. package/package.json +1 -1
  38. package/plugins/postProcess.js +2 -9
  39. package/plugins/uiSystem.js +84 -24
  40. package/src/engine.js +11 -11
  41. package/src/engineAudio.js +7 -13
  42. package/src/engineDraw.js +1 -1
  43. package/src/engineInput.js +7 -3
  44. package/src/engineMedals.js +19 -5
  45. package/src/engineObject.js +8 -5
  46. package/src/engineTileLayer.js +8 -7
  47. package/src/engineUtilities.js +59 -10
  48. package/examples/js13k/build/index.html +0 -1
  49. package/examples/js13k/build/index.js +0 -1
  50. package/examples/js13k/build/tiles.png +0 -0
  51. package/examples/js13k/game - Copy.zip +0 -0
  52. package/examples/js13k/game.zip +0 -0
  53. package/examples/starter/build/index.html +0 -2
  54. package/examples/starter/build/index.js +0 -1
  55. package/examples/starter/build/tiles.png +0 -0
  56. package/examples/starter/game.zip +0 -0
  57. package/examples/typescript/build/build/littlejs.esm.js +0 -4327
  58. package/examples/typescript/build/dist/littlejs.esm.js +0 -4425
  59. package/examples/typescript/build/examples/typescript/build.js +0 -24
  60. package/examples/typescript/build/examples/typescript/game.js +0 -100
  61. package/examples/typescript/build/examples/typescript/test/build/littlejs.esm.js +0 -3934
  62. package/examples/typescript/build/examples/typescript/test/examples/typescript/build.js +0 -86
  63. package/examples/typescript/build/examples/typescript/test/examples/typescript/game.js +0 -92
package/dist/littlejs.js CHANGED
@@ -671,7 +671,8 @@ function formatTime(t) { return (t/60|0) + ':' + (t%60<10?'0':'') + (t%60|0); }
671
671
  * @memberof Random */
672
672
  function rand(valueA=1, valueB=0) { return valueB + Math.random() * (valueA-valueB); }
673
673
 
674
- /** Returns a floored random value the two values passed in
674
+ /** Returns a floored random value between the two values passed in
675
+ * The upper bound is exclusive. (If 2 is passed in, result will be 0 or 1)
675
676
  * @param {Number} valueA
676
677
  * @param {Number} [valueB]
677
678
  * @return {Number}
@@ -800,18 +801,24 @@ class Vector2
800
801
  * @param {Number} [y] - Y axis location */
801
802
  constructor(x=0, y=0)
802
803
  {
803
- ASSERT(typeof x == 'number' && typeof y == 'number');
804
804
  /** @property {Number} - X axis location */
805
805
  this.x = x;
806
806
  /** @property {Number} - Y axis location */
807
807
  this.y = y;
808
+ ASSERT(this.isValid());
808
809
  }
809
810
 
810
811
  /** Sets values of this vector and returns self
811
812
  * @param {Number} [x] - X axis location
812
813
  * @param {Number} [y] - Y axis location
813
814
  * @return {Vector2} */
814
- set(x=0, y=0) { this.x=x; this.y=y; return this; }
815
+ set(x=0, y=0)
816
+ {
817
+ this.x = x;
818
+ this.y = y;
819
+ ASSERT(this.isValid());
820
+ return this;
821
+ }
815
822
 
816
823
  /** Returns a new vector that is a copy of this
817
824
  * @return {Vector2} */
@@ -1003,6 +1010,14 @@ class Vector2
1003
1010
  if (debug)
1004
1011
  return `(${(this.x<0?'':' ') + this.x.toFixed(digits)},${(this.y<0?'':' ') + this.y.toFixed(digits)} )`;
1005
1012
  }
1013
+
1014
+ /** Checks if this is a valid vector
1015
+ * @return {Boolean} */
1016
+ isValid()
1017
+ {
1018
+ return typeof this.x == 'number' && !isNaN(this.x)
1019
+ && typeof this.y == 'number' && !isNaN(this.y);
1020
+ }
1006
1021
  }
1007
1022
 
1008
1023
  ///////////////////////////////////////////////////////////////////////////////
@@ -1063,6 +1078,7 @@ class Color
1063
1078
  this.b = b;
1064
1079
  /** @property {Number} - Alpha */
1065
1080
  this.a = a;
1081
+ ASSERT(this.isValid());
1066
1082
  }
1067
1083
 
1068
1084
  /** Sets values of this color and returns self
@@ -1072,7 +1088,14 @@ class Color
1072
1088
  * @param {Number} [a] - alpha
1073
1089
  * @return {Color} */
1074
1090
  set(r=1, g=1, b=1, a=1)
1075
- { this.r=r; this.g=g; this.b=b; this.a=a; return this; }
1091
+ {
1092
+ this.r = r;
1093
+ this.g = g;
1094
+ this.b = b;
1095
+ this.a = a;
1096
+ ASSERT(this.isValid());
1097
+ return this;
1098
+ }
1076
1099
 
1077
1100
  /** Returns a new color that is a copy of this
1078
1101
  * @return {Color} */
@@ -1155,6 +1178,7 @@ class Color
1155
1178
  this.g = f(p, q, h);
1156
1179
  this.b = f(p, q, h - 1/3);
1157
1180
  this.a = a;
1181
+ ASSERT(this.isValid());
1158
1182
  return this;
1159
1183
  }
1160
1184
 
@@ -1182,7 +1206,6 @@ class Color
1182
1206
  else if (b == max)
1183
1207
  h = (r - g) / d + 4;
1184
1208
  }
1185
-
1186
1209
  return [h / 6, s, l, a];
1187
1210
  }
1188
1211
 
@@ -1215,11 +1238,27 @@ class Color
1215
1238
  * @return {Color} */
1216
1239
  setHex(hex)
1217
1240
  {
1218
- const fromHex = (c)=> clamp(parseInt(hex.slice(c,c+2),16)/255);
1219
- this.r = fromHex(1);
1220
- this.g = fromHex(3),
1221
- this.b = fromHex(5);
1222
- this.a = hex.length > 7 ? fromHex(7) : 1;
1241
+ ASSERT(typeof hex == 'string' && hex[0] == '#');
1242
+ ASSERT([4,5,7,9].includes(hex.length), 'Invalid hex');
1243
+
1244
+ if (hex.length < 6)
1245
+ {
1246
+ const fromHex = (c)=> clamp(parseInt(hex[c],16)/15);
1247
+ this.r = fromHex(1);
1248
+ this.g = fromHex(2),
1249
+ this.b = fromHex(3);
1250
+ this.a = hex.length == 5 ? fromHex(4) : 1;
1251
+ }
1252
+ else
1253
+ {
1254
+ const fromHex = (c)=> clamp(parseInt(hex.slice(c,c+2),16)/255);
1255
+ this.r = fromHex(1);
1256
+ this.g = fromHex(3),
1257
+ this.b = fromHex(5);
1258
+ this.a = hex.length == 9 ? fromHex(7) : 1;
1259
+ }
1260
+
1261
+ ASSERT(this.isValid());
1223
1262
  return this;
1224
1263
  }
1225
1264
 
@@ -1233,6 +1272,16 @@ class Color
1233
1272
  const a = clamp(this.a)*255<<24;
1234
1273
  return r + g + b + a;
1235
1274
  }
1275
+
1276
+ /** Checks if this is a valid color
1277
+ * @return {Boolean} */
1278
+ isValid()
1279
+ {
1280
+ return typeof this.r == 'number' && !isNaN(this.r)
1281
+ && typeof this.g == 'number' && !isNaN(this.g)
1282
+ && typeof this.b == 'number' && !isNaN(this.b)
1283
+ && typeof this.a == 'number' && !isNaN(this.a);
1284
+ }
1236
1285
  }
1237
1286
 
1238
1287
  ///////////////////////////////////////////////////////////////////////////////
@@ -1868,7 +1917,7 @@ class EngineObject
1868
1917
  * @param {Color} [color=(1,1,1,1)] - Color to apply to tile when rendered
1869
1918
  * @param {Number} [renderOrder] - Objects sorted by renderOrder before being rendered
1870
1919
  */
1871
- constructor(pos=vec2(), size=vec2(1), tileInfo, angle=0, color, renderOrder=0)
1920
+ constructor(pos=vec2(), size=vec2(1), tileInfo, angle=0, color=new Color, renderOrder=0)
1872
1921
  {
1873
1922
  // set passed in params
1874
1923
  ASSERT(isVector2(pos) && isVector2(size), 'ensure pos and size are vec2s');
@@ -1982,15 +2031,18 @@ class EngineObject
1982
2031
 
1983
2032
  // apply physics
1984
2033
  const oldPos = this.pos.copy();
1985
- this.pos.x += this.velocity.x *= this.damping;
1986
- this.pos.y += this.velocity.y = this.damping * this.velocity.y
1987
- + gravity * this.gravityScale;
2034
+ this.velocity.x *= this.damping;
2035
+ this.velocity.y *= this.damping;
2036
+ if (this.mass) // dont apply gravity to static objects
2037
+ this.velocity.y += gravity * this.gravityScale;
2038
+ this.pos.x += this.velocity.x;
2039
+ this.pos.y += this.velocity.y;
1988
2040
  this.angle += this.angleVelocity *= this.angleDamping;
1989
2041
 
1990
2042
  // physics sanity checks
1991
2043
  ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
1992
2044
  ASSERT(this.damping >= 0 && this.damping <= 1);
1993
- if (!enablePhysicsSolver || !this.mass) // dont do collision for fixed objects
2045
+ if (!enablePhysicsSolver || !this.mass) // dont do collision for static objects
1994
2046
  return;
1995
2047
 
1996
2048
  const wasMovingDown = this.velocity.y < 0;
@@ -2351,7 +2403,7 @@ let drawCount;
2351
2403
  * tile(2) // a tile at index 2 using the default tile size of 16
2352
2404
  * tile(5, 8) // a tile at index 5 using a tile size of 8
2353
2405
  * tile(1, 16, 3) // a tile at index 1 of size 16 on texture 3
2354
- * tile(vec2(4,8), vec2(30,10)) // a tile at pixel location (4,8) with a size of (30,10)
2406
+ * tile(vec2(4,8), vec2(30,10)) // a tile at index (4,8) with a size of (30,10)
2355
2407
  * @memberof Draw
2356
2408
  */
2357
2409
  function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0)
@@ -2900,7 +2952,7 @@ function keyWasReleased(key, device=0)
2900
2952
 
2901
2953
  /** Clears all input
2902
2954
  * @memberof Input */
2903
- function clearInput() { inputData = [[]]; }
2955
+ function clearInput() { inputData = [[]]; touchGamepadButtons = []; }
2904
2956
 
2905
2957
  /** Returns true if mouse button is down
2906
2958
  * @function
@@ -3065,6 +3117,7 @@ function inputInit()
3065
3117
  onmousemove = (e)=> mousePosScreen = mouseToScreen(e);
3066
3118
  onwheel = (e)=> mouseWheel = e.ctrlKey ? 0 : sign(e.deltaY);
3067
3119
  oncontextmenu = (e)=> false; // prevent right click menu
3120
+ onblur = (e) => clearInput(); // reset input when focus is lost
3068
3121
 
3069
3122
  // init touch input
3070
3123
  if (isTouchDevice && touchInputEnable)
@@ -3263,10 +3316,13 @@ function touchInputInit()
3263
3316
  if (touching)
3264
3317
  {
3265
3318
  touchGamepadTimer.set();
3266
- if (paused)
3319
+ if (paused && !wasTouching)
3267
3320
  {
3268
3321
  // touch anywhere to press start when paused
3269
3322
  touchGamepadButtons[9] = 1;
3323
+
3324
+ // call default touch handler so normal touch events still work
3325
+ handleTouchDefault(e);
3270
3326
  return;
3271
3327
  }
3272
3328
  }
@@ -3291,7 +3347,7 @@ function touchInputInit()
3291
3347
  const button = touchPos.subtract(buttonCenter).direction();
3292
3348
  touchGamepadButtons[button] = 1;
3293
3349
  }
3294
- else if (touchPos.distance(startCenter) < touchGamepadSize)
3350
+ else if (touchPos.distance(startCenter) < touchGamepadSize && !wasTouching)
3295
3351
  {
3296
3352
  // virtual start button in center
3297
3353
  touchGamepadButtons[9] = 1;
@@ -3379,7 +3435,7 @@ function touchGamepadRender()
3379
3435
  /** Audio context used by the engine
3380
3436
  * @type {AudioContext}
3381
3437
  * @memberof Audio */
3382
- let audioContext;
3438
+ let audioContext = new AudioContext;
3383
3439
 
3384
3440
  /** Master gain node for all audio to pass through
3385
3441
  * @type {GainNode}
@@ -3390,14 +3446,10 @@ function audioInit()
3390
3446
  {
3391
3447
  if (!soundEnable || headlessMode) return;
3392
3448
 
3393
- // create audio context
3394
- audioContext = new AudioContext;
3395
-
3396
- // create and connect gain node
3397
3449
  // (createGain is more widely spported then GainNode construtor)
3398
3450
  audioGainNode = audioContext.createGain();
3399
3451
  audioGainNode.connect(audioContext.destination);
3400
- setSoundVolume(soundVolume); // update gain volume
3452
+ audioGainNode.gain.value = soundVolume; // set starting value
3401
3453
  }
3402
3454
 
3403
3455
  ///////////////////////////////////////////////////////////////////////////////
@@ -3432,12 +3484,15 @@ class Sound
3432
3484
 
3433
3485
  /** @property {Number} - How much to randomize frequency each time sound plays */
3434
3486
  this.randomness = 0;
3487
+
3488
+ /** @property {GainNode} - Gain node for this sound */
3489
+ this.gainNode = audioContext.createGain();
3435
3490
 
3436
3491
  if (zzfxSound)
3437
3492
  {
3438
3493
  // generate zzfx sound now for fast playback
3439
3494
  const defaultRandomness = .05;
3440
- this.randomness = zzfxSound[1] || defaultRandomness;
3495
+ this.randomness = zzfxSound[1] != undefined ? zzfxSound[1] : defaultRandomness;
3441
3496
  zzfxSound[1] = 0; // generate without randomness
3442
3497
  this.sampleChannels = [zzfxG(...zzfxSound)];
3443
3498
  this.sampleRate = zzfxR;
@@ -3478,18 +3533,13 @@ class Sound
3478
3533
 
3479
3534
  // play the sound
3480
3535
  const playbackRate = pitch + pitch * this.randomness*randomnessScale*rand(-1,1);
3481
- this.gainNode = audioContext.createGain();
3482
3536
  return this.source = playSamples(this.sampleChannels, volume, playbackRate, pan, loop, this.sampleRate, this.gainNode);
3483
3537
  }
3484
3538
 
3485
3539
  /** Set the sound volume
3486
3540
  * @param {Number} [volume] - How much to scale volume by
3487
3541
  */
3488
- setVolume(volume=1)
3489
- {
3490
- if (this.gainNode)
3491
- this.gainNode.gain.value = volume;
3492
- }
3542
+ setVolume(volume=1) { this.gainNode.gain.value = volume; }
3493
3543
 
3494
3544
  /** Stop the last instance of this sound that was played */
3495
3545
  stop()
@@ -3973,18 +4023,18 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
3973
4023
 
3974
4024
 
3975
4025
 
3976
- /** The tile collision layer array, use setTileCollisionData and getTileCollisionData to access
4026
+ /** The tile collision layer grid, use setTileCollisionData and getTileCollisionData to access
3977
4027
  * @type {Array}
3978
4028
  * @memberof TileCollision */
3979
4029
  let tileCollision = [];
3980
4030
 
3981
- /** Size of the tile collision layer
4031
+ /** Size of the tile collision layer 2d grid
3982
4032
  * @type {Vector2}
3983
4033
  * @memberof TileCollision */
3984
4034
  let tileCollisionSize = vec2();
3985
4035
 
3986
4036
  /** Clear and initialize tile collision
3987
- * @param {Vector2} size
4037
+ * @param {Vector2} size - width and height of tile collision 2d grid
3988
4038
  * @memberof TileCollision */
3989
4039
  function initTileCollision(size)
3990
4040
  {
@@ -3994,7 +4044,7 @@ function initTileCollision(size)
3994
4044
  tileCollision[i] = 0;
3995
4045
  }
3996
4046
 
3997
- /** Set tile collision data
4047
+ /** Set tile collision data for a given cell in the grid
3998
4048
  * @param {Vector2} pos
3999
4049
  * @param {Number} [data]
4000
4050
  * @memberof TileCollision */
@@ -4003,7 +4053,7 @@ function setTileCollisionData(pos, data=0)
4003
4053
  pos.arrayCheck(tileCollisionSize) && (tileCollision[(pos.y|0)*tileCollisionSize.x+pos.x|0] = data);
4004
4054
  }
4005
4055
 
4006
- /** Get tile collision data
4056
+ /** Get tile collision data for a given cell in the grid
4007
4057
  * @param {Vector2} pos
4008
4058
  * @return {Number}
4009
4059
  * @memberof TileCollision */
@@ -4034,7 +4084,8 @@ function tileCollisionTest(pos, size=vec2(), object)
4034
4084
  return false;
4035
4085
  }
4036
4086
 
4037
- /** Return the center of first tile hit (does not return the exact intersection)
4087
+ /** Return the center of first tile hit, undefined if nothing was hit.
4088
+ * This does not return the exact intersection, but the center of the tile hit.
4038
4089
  * @param {Vector2} posStart
4039
4090
  * @param {Vector2} posEnd
4040
4091
  * @param {EngineObject} [object]
@@ -4279,8 +4330,8 @@ class TileLayer extends EngineObject
4279
4330
  const d = this.getData(layerPos);
4280
4331
  if (d.tile != undefined)
4281
4332
  {
4282
- const pos = this.pos.add(layerPos).add(vec2(.5));
4283
4333
  ASSERT(mainContext == this.context, 'must call redrawStart() before drawing tiles');
4334
+ const pos = layerPos.add(vec2(.5));
4284
4335
  const tileInfo = tile(d.tile, s, this.tileInfo.textureIndex);
4285
4336
  drawTile(pos, vec2(1), tileInfo, d.color, d.direction*PI/2, d.mirror);
4286
4337
  }
@@ -4709,7 +4760,7 @@ function medalsInit(saveName)
4709
4760
  // check if medals are unlocked
4710
4761
  medalsSaveName = saveName;
4711
4762
  if (!debugMedals)
4712
- medalsForEach(medal=> medal.unlocked = (localStorage[medal.storageKey()] | 0));
4763
+ medalsForEach(medal=> medal.unlocked = !!localStorage[medal.storageKey()]);
4713
4764
 
4714
4765
  // engine automatically renders medals
4715
4766
  engineAddPlugin(undefined, medalsRender);
@@ -4772,14 +4823,28 @@ class Medal
4772
4823
  constructor(id, name, description='', icon='🏆', src)
4773
4824
  {
4774
4825
  ASSERT(id >= 0 && !medals[id]);
4775
-
4776
- // save attributes and add to list of medals
4777
- medals[this.id = id] = this;
4826
+
4827
+ /** @property {Number} - The unique identifier of the medal */
4828
+ this.id = id;
4829
+
4830
+ /** @property {String} - Name of the medal */
4778
4831
  this.name = name;
4832
+
4833
+ /** @property {String} - Description of the medal */
4779
4834
  this.description = description;
4835
+
4836
+ /** @property {String} - Icon for the medal */
4780
4837
  this.icon = icon;
4838
+
4839
+ /** @property {Boolean} - Is the medal unlocked? */
4840
+ this.unlocked = false;
4841
+
4842
+ // load the source image if provided
4781
4843
  if (src)
4782
4844
  (this.image = new Image).src = src;
4845
+
4846
+ // add this to list of medals
4847
+ medals[id] = this;
4783
4848
  }
4784
4849
 
4785
4850
  /** Unlocks a medal if not already unlocked */
@@ -4790,7 +4855,7 @@ class Medal
4790
4855
 
4791
4856
  // save the medal
4792
4857
  ASSERT(medalsSaveName, 'save name must be set');
4793
- localStorage[this.storageKey()] = this.unlocked = 1;
4858
+ localStorage[this.storageKey()] = this.unlocked = true;
4794
4859
  medalsDisplayQueue.push(this);
4795
4860
  }
4796
4861
 
@@ -5198,7 +5263,7 @@ const engineName = 'LittleJS';
5198
5263
  * @type {String}
5199
5264
  * @default
5200
5265
  * @memberof Engine */
5201
- const engineVersion = '1.10.4';
5266
+ const engineVersion = '1.10.7';
5202
5267
 
5203
5268
  /** Frames per second to update
5204
5269
  * @type {Number}
@@ -5261,6 +5326,8 @@ const pluginUpdateList = [], pluginRenderList = [];
5261
5326
  * @memberof Engine */
5262
5327
  function engineAddPlugin(updateFunction, renderFunction)
5263
5328
  {
5329
+ ASSERT(!pluginUpdateList.includes(updateFunction));
5330
+ ASSERT(!pluginRenderList.includes(renderFunction));
5264
5331
  updateFunction && pluginUpdateList.push(updateFunction);
5265
5332
  renderFunction && pluginRenderList.push(renderFunction);
5266
5333
  }
@@ -5269,12 +5336,12 @@ function engineAddPlugin(updateFunction, renderFunction)
5269
5336
  // Main engine functions
5270
5337
 
5271
5338
  /** Startup LittleJS engine with your callback functions
5272
- * @param {Function} gameInit - Called once after the engine starts up, setup the game
5273
- * @param {Function} gameUpdate - Called every frame at 60 frames per second, handle input and update the game state
5274
- * @param {Function} gameUpdatePost - Called after physics and objects are updated, setup camera and prepare for render
5275
- * @param {Function} gameRender - Called before objects are rendered, draw any background effects that appear behind objects
5276
- * @param {Function} gameRenderPost - Called after objects are rendered, draw effects or hud that appear above all objects
5277
- * @param {Array} [imageSources=[]] - Image to load
5339
+ * @param {Function|function():Promise} gameInit - Called once after the engine starts up
5340
+ * @param {Function} gameUpdate - Called every frame before objects are updated
5341
+ * @param {Function} gameUpdatePost - Called after physics and objects are updated, even when paused
5342
+ * @param {Function} gameRender - Called before objects are rendered, for drawing the background
5343
+ * @param {Function} gameRenderPost - Called after objects are rendered, useful for drawing UI
5344
+ * @param {Array} [imageSources=[]] - List of images to load
5278
5345
  * @param {HTMLElement} [rootElement] - Root element to attach to, the document body by default
5279
5346
  * @memberof Engine */
5280
5347
  function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=[], rootElement=document.body)
@@ -5424,8 +5491,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
5424
5491
 
5425
5492
  function startEngine()
5426
5493
  {
5427
- gameInit();
5428
- engineUpdate();
5494
+ new Promise((resolve) => resolve(gameInit())).then(engineUpdate);
5429
5495
  }
5430
5496
 
5431
5497
  if (headlessMode)
@@ -5440,7 +5506,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
5440
5506
  'width:100vw;height:100vh;' + // fill the window
5441
5507
  'display:flex;' + // use flexbox
5442
5508
  'align-items:center;' + // horizontal center
5443
- (canvasPixelated ? 'image-rendering:pixelated;' : '') + // pixel art
5444
5509
  'justify-content:center;' + // vertical center
5445
5510
  'background:#000;' + // set background color
5446
5511
  'user-select:none;' + // prevent hold to select
@@ -5778,4 +5843,5 @@ function drawEngineSplashScreen(t)
5778
5843
  }
5779
5844
 
5780
5845
  x.restore();
5781
- }
5846
+ }
5847
+