litecanvas 0.83.0 → 0.83.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,12 +2,15 @@
2
2
 
3
3
  # Litecanvas
4
4
 
5
+ [![NPM Version](https://flat.badgen.net/npm/v/litecanvas?scale=1&label=NPM)](https://www.npmjs.com/package/litecanvas/)
6
+
5
7
  Litecanvas is a lightweight HTML5 canvas 2D engine suitable for small web games, prototypes, game jams, animations, creative coding, learning game programming and game design, etc.
6
8
 
7
9
  :warning: **This project is still under development. All feedback is appreciated!** :warning:
8
10
 
9
- [![Discord Server](https://flat.badgen.net/static/CHAT/ON%20DISCORD/5865f2?scale=1.5)](https://discord.com/invite/r2c3rGsvH3)
10
- [![Discord Server](https://flat.badgen.net/static/FOLLOW/ON%20ITCH.IO/fa5c5c?scale=1.5)](https://bills.itch.io/litecanvas)
11
+ [![Itch](https://flat.badgen.net/static/FOLLOW/ON%20ITCH.IO/fa5c5c?scale=1.25)](https://bills.itch.io/litecanvas)
12
+ [![Discord Server](https://flat.badgen.net/static/CHAT/ON%20DISCORD/5865f2?scale=1.25&icon=discord)](https://discord.com/invite/r2c3rGsvH3)
13
+ [![Playground](https://flat.badgen.net/static/CODE/ON%20PLAYGROUND/5f3dc4?scale=1.25)](https://litecanvas.js.org/)
11
14
 
12
15
  ### Features
13
16
 
@@ -38,8 +41,10 @@ If you prefer, you can manually install via [NPM](https://www.npmjs.com/package/
38
41
  npm install litecanvas
39
42
  ```
40
43
 
44
+ ### Show me the code!
45
+
41
46
  ```js
42
- // import the package or put the CDN script in your HTML
47
+ // import the package or put a script tag in your HTML
43
48
  // CDN: https://unpkg.com/litecanvas/dist/dist.dev.js
44
49
  import litecanvas from 'litecanvas'
45
50
 
@@ -49,43 +54,44 @@ litecanvas({
49
54
  loop: { init, update, draw, tapped },
50
55
  })
51
56
 
57
+ // this function runs once at the beginning
52
58
  function init() {
53
- // this function run once
54
- // before the game starts
55
- bg = 0
56
- color = 3
57
- radius = 32
58
- posx = CX // center X or (canvas width / 2)
59
- posy = CY // center Y or (canvas width / 2)
59
+ bg = 0 // the color #0 (black)
60
+ color = 3 // the color #3 (white)
61
+ radius = W / 10 // the canvas width/10
62
+ posx = CX // center X (or canvas width/2)
63
+ posy = CY // center Y (or canvas width/2)
60
64
  }
61
65
 
62
- // this function detect taps/clicks
63
- // and changes the circle position
66
+ // this function detect clicks/touches
64
67
  function tapped(x, y) {
68
+ // changes the circle position
69
+ // based on the position of the tap
65
70
  posx = x
66
71
  posy = y
67
72
  }
68
73
 
69
- // this function controls the game logic
74
+ // put the game logic in this function
70
75
  function update(dt) {
71
76
  // make the circle falls 100 pixels per second
72
- posy += 100 * dt
77
+ posy += 200 * dt
73
78
  }
74
79
 
75
- // this function render the game scene
80
+ // put the game rendering in this function
76
81
  function draw() {
77
82
  cls(bg) // clear the screen
78
83
  circfill(posx, posy, radius, color) // draw a circle
84
+ text(10, 10, 'Tap anywhere') // draw a text
79
85
  }
80
86
  ```
81
87
 
82
- ## Docs
88
+ [Play with this code in the playground](https://litecanvas.js.org?c=eJx9k91u4yAQhe%2F9FCP1ovauFZL2LlKu9hFaadtLDBNDQwDBeOOoyrsv4KR2V9FasuSfjzNnDgNj8EI8EHArISINHkghoO21xYoxMMiDhaMLuAVF5OOWMaMJBbd%2FeFx9xJULPeOdG2il6Ggekghp28dqpurPCtJlnPNb%2BARtNbUweMkJW5CBn1og7j1KuLTVpalyXVI6wn6wgrSzEAYbwVmBwKkY7DAZtKlO9cVk2bqBqVbXww7WUIQQhDMuwMMa6s5wcWgKMn3cwfM%2F1DPUJ5W8T1TgUg8xYb%2BBwWZWLI3BSUtSbLMuqHdxTOCvtwwJtIQB3qBOmt%2Fop%2BZGnzP9vqDf79KXO4FITOESCKPFITJyg1AY5yymOOuxhfMtkVxFcdtjnBrQQRjMLnRecUM6HtM2ZAU1%2FwS3L%2B9JddnouOzjfLXph2mDen7EtOO9FmljvpufbU4zUEtamDzyAy4d7rkxMSW%2FBq9HTI8%2BBRVROCvn%2Bj938JSIHyDpno%2BAVmJI0%2FIfL3kOv8ZHmFh3fVNCyyegSEUREKeksre9NqbOUbTFQ3sdlXaao7I2awK%2FdlIWEo5Ub9Yt5Pvxlft08M4nhQEflysyVl3%2BAgslJEg%3D)
83
89
 
84
- Check out our [Cheatsheet](https://litecanvas.js.org/about.html).
90
+ https://github.com/user-attachments/assets/854ac6bd-724f-4da8-bb3c-bc04dba5d8c8
85
91
 
86
- ## Basic Demos
92
+ ## Demos
87
93
 
88
- Try some demos in our playground:
94
+ Try some demos in the playground:
89
95
 
90
96
  - [Pong](https://litecanvas.js.org?c=eJy1Vlly20YQ%2FccpOl8ATBACuEiWYslFM5DlKkdMkUwkJpVKwcCQnAoEoIChpdiWr%2BAT%2BC%2BHyHlygVwh3TODTZYU%2F0QsDdELenm9DBMmIA%2FjCzgGf%2BA5BuAf0mdEj2vykkivEa%2BQHg01HbNSkALpKc6bMElaj6vmccHfsZZpYk3STUK8yhovpLeaWjVUmTMWIzmoQimjrGi9m%2FA1K5EcKlKwG0EOta4ICyFfX4dJyQwj4YJFYfo2LK33UuOax2J7BMMKhy3jm604gtFTZNzahrG3B9NdKbIr%2BPnd6SWU2S6NS1hnBYgtL2ETXjHSyQsmBGdFn29SjM%2BIsrQU8GL24%2Fk0QPe%2FOOCAz4b05XpDOgbIcGBAHAcOR54WVB8XJe6%2B0t%2F%2F9duHfSyWk%2FmSXHju2EFUYIxIyddGeAzbXsYHnvYsD%2B3IGz1m%2FsXk9evfZqeni%2Bk8CM7Jj%2B8OfZnOGB14rkdeyQ8eB9KbpPqH7iGe%2B3TSx3N9v3oayPfkOZKnTxka610aCZ6lwFMuLBveN42FfqfB%2BTKYXzYdVvNW0Iez4NXLsyXswajTBqhz8eq75RkK%2FIFx2%2FIhwjxnsXXjwB%2BVJ74G6xvdMhWv20Wi2LGGvb6xJPh2zUIEd0UqydvOnHz8aN1glHLq9mBgd0LZ5XEomBWL%2BwNRRgErJLjAsSmjgrH0ea2pJ%2BAYR6KtTJ0J2VtWPDekKrKukMS2ZRRHnLD2pCesyC05zSpmVVm7fjXOUlOglmi9j2SoDaqY6pCk0WcUjzbvSRHDGWzkPQXHiapQrarqpbAyaouq4r1moZzokrcLVbWKv%2B91eNQqBw2rWhnquw9%2Bp6Tdhrd1MSscVK2kVcizklMBW23aO1bL7IneW08gFq2OVeJVV6zWGCL7BndL1N5W2qfiK5%2FYLnew1o7byCgIP3zQQT2rZW2wVJzH0G%2FSbwKoG%2F22KZpK4UFjcmc%2FaqpOKNqy6HeVT5QlCS9pCq652LYbk1yitGCRUDk6%2BmKpA2g%2Fqdala0qeF7iI7HsCbCWr7pEeXXJfEbUEQElt1SZytXcHOS7C63pvRUlpefaji4W2VJjgurXMiKWCFaYD5hUnCEy7o1Vikla11LoiSy9Gp9qGaGM5%2BQGWM3U1oM2hfbeWqvVPaEKbcAjqNU8S60sw6edBbUdmx4tI6j5Ummp3PJDBfRhIhAiCbZhueLq5g4Hl4%2B1F%2F%2Bbfn%2F%2F8569PYLoFy1koVDa2A6P77bI0fsRqtW8q65Zp4jTJ7rBdzHtBUVl4E3v2XST%2F70piVAO8Xc2Xk%2B8DmP0UzM1ODb4wh%2FvEc5%2BO%2F8tqT6G4mM7mwREl%2B1UpY6f%2FC73Is6Q%3D)
91
97
  - [Bouncing Ball](https://litecanvas.js.org?c=eJxtUstugzAQvPMVewTiBCdtpVYpPVStSu6ReraMiSy5gIyhRUn%2BvQZvg0NzsGTveGdmH0oYqKtGGlmVkEIneLimlNgTkQDsW1Vcmn64HzTr8KpZLtvG%2Fr9%2FDAIljeCs7FgTRkFQtCUfyWQpTRjB0WNBgc%2Fd2z6LNyR7331k%2B2QTbSd2%2FEIRtNDZ42zrnBkR5sbx%2Fhlf%2FcAivajYVwy58fH%2BCu8d7hlzBGhhyvcyPHhKTxJ4raw3AVVRgMgPorFRWUA4OVtgr15gLBtOJ8%2F2EsFnoK6iK0txCsv19kaUrp4exrDXgBS4Yl%2B1p0xwTMQpo1ZkE89zl7Y%2BuPjEzs%2F99KOf%2F9LDyFwKKowC%2FtRyzb5xE7hqQjrOm0vNC6mUb3jiJGj9brYAw27YwnrHpoVpdQnHIWIlfwGU6d0i)
package/dist/dist.dev.js CHANGED
@@ -32,9 +32,7 @@
32
32
  function litecanvas(settings = {}) {
33
33
  const root = globalThis, math = Math, TWO_PI = math.PI * 2, raf = requestAnimationFrame, _browserEventListeners = [], on = (elem, evt, callback) => {
34
34
  elem.addEventListener(evt, callback, false);
35
- _browserEventListeners.push(
36
- () => elem.removeEventListener(evt, callback, false)
37
- );
35
+ _browserEventListeners.push(() => elem.removeEventListener(evt, callback, false));
38
36
  }, isNumber = Number.isFinite, defaults = {
39
37
  width: null,
40
38
  height: null,
@@ -93,7 +91,7 @@
93
91
  *
94
92
  * @type {number}
95
93
  */
96
- HALF_PI: math.PI / 2,
94
+ HALF_PI: TWO_PI / 4,
97
95
  /**
98
96
  * Calculates a linear (interpolation) value over t%.
99
97
  *
@@ -158,16 +156,13 @@
158
156
  * @param {number} max
159
157
  * @returns {number}
160
158
  */
161
- clamp: (value, min, max) => {
159
+ clamp: (value, min2, max2) => {
162
160
  DEV: assert(isNumber(value), "clamp: 1st param must be a number");
163
- DEV: assert(isNumber(min), "clamp: 2nd param must be a number");
164
- DEV: assert(isNumber(max), "clamp: 3rd param must be a number");
165
- DEV: assert(
166
- max > min,
167
- "randi: the 2nd param must be less than the 3rd param"
168
- );
169
- if (value < min) return min;
170
- if (value > max) return max;
161
+ DEV: assert(isNumber(min2), "clamp: 2nd param must be a number");
162
+ DEV: assert(isNumber(max2), "clamp: 3rd param must be a number");
163
+ DEV: assert(max2 > min2, "clamp: the 2nd param must be less than the 3rd param");
164
+ if (value < min2) return min2;
165
+ if (value > max2) return max2;
171
166
  return value;
172
167
  },
173
168
  /**
@@ -178,19 +173,12 @@
178
173
  * @param {number} max
179
174
  * @returns {number}
180
175
  */
181
- wrap: (value, min, max) => {
176
+ wrap: (value, min2, max2) => {
182
177
  DEV: assert(isNumber(value), "wrap: 1st param must be a number");
183
- DEV: assert(isNumber(min), "wrap: 2nd param must be a number");
184
- DEV: assert(isNumber(max), "wrap: 3rd param must be a number");
185
- DEV: assert(
186
- max > min,
187
- "randi: the 2nd param must be less than the 3rd param"
188
- );
189
- DEV: assert(
190
- max !== min,
191
- "randi: the 2nd param must be not equal to the 3rd param"
192
- );
193
- return value - (max - min) * math.floor((value - min) / (max - min));
178
+ DEV: assert(isNumber(min2), "wrap: 2nd param must be a number");
179
+ DEV: assert(isNumber(max2), "wrap: 3rd param must be a number");
180
+ DEV: assert(max2 > min2, "wrap: the 2nd param must be less than the 3rd param");
181
+ return value - (max2 - min2) * math.floor((value - min2) / (max2 - min2));
194
182
  },
195
183
  /**
196
184
  * Re-maps a number from one range to another.
@@ -209,6 +197,7 @@
209
197
  DEV: assert(isNumber(stop1), "map: 3rd param must be a number");
210
198
  DEV: assert(isNumber(start2), "map: 4th param must be a number");
211
199
  DEV: assert(isNumber(stop2), "map: 5th param must be a number");
200
+ DEV: assert(max !== min, "map: the 3rd param must be different than the 2nd param");
212
201
  const result = (value - start1) / (stop1 - start1) * (stop2 - start2) + start2;
213
202
  return withinBounds ? instance.clamp(result, start2, stop2) : result;
214
203
  },
@@ -233,10 +222,19 @@
233
222
  *
234
223
  * @param {number} from - the lower bound
235
224
  * @param {number} to - the higher bound
236
- * @param {number} t - the amount
237
- * @param {(n: number) => number} fn - the periodic function (which default to `Math.sin`)
225
+ * @param {number} t - value passed to the periodic function
226
+ * @param {(n: number) => number} [fn] - the periodic function (which default to `Math.sin`)
238
227
  */
239
- wave: (from, to, t, fn = Math.sin) => from + (fn(t) + 1) / 2 * (to - from),
228
+ wave: (from, to, t, fn = Math.sin) => {
229
+ DEV: assert(isNumber(from), "wave: 1st param must be a number");
230
+ DEV: assert(isNumber(to), "wave: 2nd param must be a number");
231
+ DEV: assert(isNumber(t), "wave: 3rd param must be a number");
232
+ DEV: assert(
233
+ "function" === typeof fn,
234
+ "wave: 4rd param must be a function (n: number) => number"
235
+ );
236
+ return from + (fn(t) + 1) / 2 * (to - from);
237
+ },
240
238
  /** RNG API */
241
239
  /**
242
240
  * Generates a pseudorandom float between min (inclusive) and max (exclusive)
@@ -246,18 +244,15 @@
246
244
  * @param {number} [max=1.0]
247
245
  * @returns {number} the random number
248
246
  */
249
- rand: (min = 0, max = 1) => {
250
- DEV: assert(isNumber(min), "rand: 1st param must be a number");
251
- DEV: assert(isNumber(max), "rand: 2nd param must be a number");
252
- DEV: assert(
253
- max > min,
254
- "rand: the 1st param must be less than the 2nd param"
255
- );
247
+ rand: (min2 = 0, max2 = 1) => {
248
+ DEV: assert(isNumber(min2), "rand: 1st param must be a number");
249
+ DEV: assert(isNumber(max2), "rand: 2nd param must be a number");
250
+ DEV: assert(max2 > min2, "rand: the 1st param must be less than the 2nd param");
256
251
  const a = 1664525;
257
252
  const c = 1013904223;
258
253
  const m = 4294967296;
259
254
  _rngSeed = (a * _rngSeed + c) % m;
260
- return _rngSeed / m * (max - min) + min;
255
+ return _rngSeed / m * (max2 - min2) + min2;
261
256
  },
262
257
  /**
263
258
  * Generates a pseudorandom integer between min (inclusive) and max (inclusive)
@@ -266,14 +261,11 @@
266
261
  * @param {number} [max=1]
267
262
  * @returns {number} the random number
268
263
  */
269
- randi: (min = 0, max = 1) => {
270
- DEV: assert(isNumber(min), "randi: 1st param must be a number");
271
- DEV: assert(isNumber(max), "randi: 2nd param must be a number");
272
- DEV: assert(
273
- max > min,
274
- "randi: the 1st param must be less than the 2nd param"
275
- );
276
- return math.floor(instance.rand(min, max + 1));
264
+ randi: (min2 = 0, max2 = 1) => {
265
+ DEV: assert(isNumber(min2), "randi: 1st param must be a number");
266
+ DEV: assert(isNumber(max2), "randi: 2nd param must be a number");
267
+ DEV: assert(max2 > min2, "randi: the 1st param must be less than the 2nd param");
268
+ return math.floor(instance.rand(min2, max2 + 1));
277
269
  },
278
270
  /**
279
271
  * Initializes the random number generator with an explicit seed value.
@@ -303,13 +295,7 @@
303
295
  if (null == color) {
304
296
  _ctx.clearRect(0, 0, _ctx.canvas.width, _ctx.canvas.height);
305
297
  } else {
306
- instance.rectfill(
307
- 0,
308
- 0,
309
- _ctx.canvas.width,
310
- _ctx.canvas.height,
311
- color
312
- );
298
+ instance.rectfill(0, 0, _ctx.canvas.width, _ctx.canvas.height, color);
313
299
  }
314
300
  },
315
301
  /**
@@ -321,14 +307,13 @@
321
307
  * @param {number} height
322
308
  * @param {number} [color=0] the color index
323
309
  * @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
310
+ *
311
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/roundRect
324
312
  */
325
313
  rect(x, y, width, height, color, radii) {
326
314
  DEV: assert(isNumber(x), "rect: 1st param must be a number");
327
315
  DEV: assert(isNumber(y), "rect: 2nd param must be a number");
328
- DEV: assert(
329
- isNumber(width) && width > 0,
330
- "rect: 3rd param must be a positive number"
331
- );
316
+ DEV: assert(isNumber(width) && width > 0, "rect: 3rd param must be a positive number");
332
317
  DEV: assert(
333
318
  isNumber(height) && height >= 0,
334
319
  "rect: 4th param must be a positive number or zero"
@@ -381,13 +366,7 @@
381
366
  "rectfill: 6th param must be a number or array of at least 2 numbers"
382
367
  );
383
368
  _ctx.beginPath();
384
- _ctx[radii ? "roundRect" : "rect"](
385
- ~~x,
386
- ~~y,
387
- ~~width,
388
- ~~height,
389
- radii
390
- );
369
+ _ctx[radii ? "roundRect" : "rect"](~~x, ~~y, ~~width, ~~height, radii);
391
370
  instance.fill(color);
392
371
  },
393
372
  /**
@@ -448,14 +427,8 @@
448
427
  line(x1, y1, x2, y2, color) {
449
428
  DEV: assert(isNumber(x1), "line: 1st param must be a number");
450
429
  DEV: assert(isNumber(y1), "line: 2nd param must be a number");
451
- DEV: assert(
452
- isNumber(x2),
453
- "line: 3rd param must be a positive number or zero"
454
- );
455
- DEV: assert(
456
- isNumber(y2),
457
- "line: 4th param must be a positive number or zero"
458
- );
430
+ DEV: assert(isNumber(x2), "line: 3rd param must be a positive number or zero");
431
+ DEV: assert(isNumber(y2), "line: 4th param must be a positive number or zero");
459
432
  DEV: assert(
460
433
  null == color || isNumber(color) && color >= 0,
461
434
  "line: 5th param must be a positive number or zero"
@@ -494,10 +467,7 @@
494
467
  Array.isArray(segments) && segments.length > 0,
495
468
  "linedash: 1st param must be an array of numbers"
496
469
  );
497
- DEV: assert(
498
- isNumber(offset),
499
- "linedash: 2nd param must be a number"
500
- );
470
+ DEV: assert(isNumber(offset), "linedash: 2nd param must be a number");
501
471
  _ctx.setLineDash(segments);
502
472
  _ctx.lineDashOffset = offset;
503
473
  },
@@ -518,10 +488,7 @@
518
488
  null == color || isNumber(color) && color >= 0,
519
489
  "text: 4th param must be a positive number or zero"
520
490
  );
521
- DEV: assert(
522
- "string" === typeof fontStyle,
523
- "text: 5th param must be a string"
524
- );
491
+ DEV: assert("string" === typeof fontStyle, "text: 5th param must be a string");
525
492
  _ctx.font = `${fontStyle} ${_fontSize}px ${_fontFamily}`;
526
493
  _ctx.fillStyle = _colors[~~color % _colors.length];
527
494
  _ctx.fillText(message, ~~x, ~~y);
@@ -532,10 +499,7 @@
532
499
  * @param {string} family
533
500
  */
534
501
  textfont(family) {
535
- DEV: assert(
536
- "string" === typeof family,
537
- "textfont: 1st param must be a string"
538
- );
502
+ DEV: assert("string" === typeof family, "textfont: 1st param must be a string");
539
503
  _fontFamily = family;
540
504
  },
541
505
  /**
@@ -561,14 +525,9 @@
561
525
  "textalign: 1st param must be null or one of the following strings: center, left, right, start or end."
562
526
  );
563
527
  DEV: assert(
564
- null == baseline || [
565
- "top",
566
- "bottom",
567
- "middle",
568
- "hanging",
569
- "alphabetic",
570
- "ideographic"
571
- ].includes(baseline),
528
+ null == baseline || ["top", "bottom", "middle", "hanging", "alphabetic", "ideographic"].includes(
529
+ baseline
530
+ ),
572
531
  "textalign: 2nd param must be null or one of the following strings: middle, top, bottom, hanging, alphabetic or ideographic."
573
532
  );
574
533
  if (align) _ctx.textAlign = align;
@@ -679,10 +638,7 @@
679
638
  */
680
639
  scale: (x, y) => {
681
640
  DEV: assert(isNumber(x), "scale: 1st param must be a number");
682
- DEV: assert(
683
- null == y || isNumber(y),
684
- "scale: 2nd param must be a number"
685
- );
641
+ DEV: assert(null == y || isNumber(y), "scale: 2nd param must be a number");
686
642
  return _ctx.scale(x, y || x);
687
643
  },
688
644
  /**
@@ -767,14 +723,13 @@
767
723
  /**
768
724
  * Turn given path into a clipping region.
769
725
  *
726
+ * Note: always call `push()` before and `pop()` after.
727
+ *
770
728
  * @param {Path2D} path
771
729
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip
772
730
  */
773
731
  clip(path) {
774
- DEV: assert(
775
- path instanceof Path2D,
776
- "clip: 1st param must be a Path2D instance"
777
- );
732
+ DEV: assert(path instanceof Path2D, "clip: 1st param must be a Path2D instance");
778
733
  _ctx.clip(path);
779
734
  },
780
735
  /** SOUND API */
@@ -795,10 +750,7 @@
795
750
  "sfx: 1st param must be an array"
796
751
  );
797
752
  DEV: assert(isNumber(pitchSlide), "sfx: 2nd param must be a number");
798
- DEV: assert(
799
- isNumber(volumeFactor),
800
- "sfx: 3rd param must be a number"
801
- );
753
+ DEV: assert(isNumber(volumeFactor), "sfx: 3rd param must be a number");
802
754
  if (root.zzfxV <= 0 || navigator.userActivation && !navigator.userActivation.hasBeenActive) {
803
755
  return false;
804
756
  }
@@ -828,15 +780,13 @@
828
780
  * @param {pluginCallback} callback
829
781
  */
830
782
  use(callback, config = {}) {
831
- DEV: assert(
832
- "function" === typeof callback,
833
- "use: 1st param must be a function"
834
- );
835
- DEV: assert(
836
- "object" === typeof config,
837
- "use: 2nd param must be an object"
838
- );
839
- _initialized ? loadPlugin(callback, config) : _plugins.push([callback, config]);
783
+ DEV: assert("function" === typeof callback, "use: 1st param must be a function");
784
+ DEV: assert("object" === typeof config, "use: 2nd param must be an object");
785
+ if (_initialized) {
786
+ loadPlugin(callback, config);
787
+ } else {
788
+ _plugins.push([callback, config]);
789
+ }
840
790
  },
841
791
  /**
842
792
  * Add a game event listener
@@ -846,14 +796,8 @@
846
796
  * @returns {Function} a function to remove the listener
847
797
  */
848
798
  listen(eventName, callback) {
849
- DEV: assert(
850
- "string" === typeof eventName,
851
- "listen: 1st param must be a string"
852
- );
853
- DEV: assert(
854
- "function" === typeof callback,
855
- "listen: 2nd param must be a function"
856
- );
799
+ DEV: assert("string" === typeof eventName, "listen: 1st param must be a string");
800
+ DEV: assert("function" === typeof callback, "listen: 2nd param must be a function");
857
801
  eventName = eventName.toLowerCase();
858
802
  _events[eventName] = _events[eventName] || /* @__PURE__ */ new Set();
859
803
  _events[eventName].add(callback);
@@ -869,10 +813,7 @@
869
813
  * @param {*} [arg4] any data to be passed over the listeners
870
814
  */
871
815
  emit(eventName, arg1, arg2, arg3, arg4) {
872
- DEV: assert(
873
- "string" === typeof eventName,
874
- "emit: 1st param must be a string"
875
- );
816
+ DEV: assert("string" === typeof eventName, "emit: 1st param must be a string");
876
817
  if (_initialized) {
877
818
  eventName = eventName.toLowerCase();
878
819
  triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
@@ -899,14 +840,9 @@
899
840
  * @param {*} value
900
841
  */
901
842
  def(key, value) {
902
- DEV: assert(
903
- "string" === typeof key,
904
- "def: 1st param must be a string"
905
- );
843
+ DEV: assert("string" === typeof key, "def: 1st param must be a string");
906
844
  DEV: if (null == value) {
907
- console.warn(
908
- `def: key "${key}" was defined as ${value} but now is null`
909
- );
845
+ console.warn(`def: key "${key}" was defined as ${value} but now is null`);
910
846
  }
911
847
  instance[key] = value;
912
848
  if (settings.global) {
@@ -946,10 +882,7 @@
946
882
  * @returns {any}
947
883
  */
948
884
  stat(n) {
949
- DEV: assert(
950
- isNumber(n) && n >= 0,
951
- "stat: 1st param must be a positive number"
952
- );
885
+ DEV: assert(isNumber(n) && n >= 0, "stat: 1st param must be a positive number");
953
886
  const list = [
954
887
  // 0
955
888
  settings,
@@ -1014,25 +947,50 @@
1014
947
  on(root, "resize", resizeCanvas);
1015
948
  }
1016
949
  if (settings.tapEvents) {
1017
- const _getXY = (pageX, pageY) => [
1018
- (pageX - _canvas.offsetLeft) / _scale,
1019
- (pageY - _canvas.offsetTop) / _scale
1020
- ], _taps = /* @__PURE__ */ new Map(), _registerTap = (id, x, y) => {
1021
- const tap = {
1022
- x,
1023
- y,
1024
- startX: x,
1025
- startY: y,
1026
- // timestamp
1027
- ts: performance.now()
1028
- };
1029
- _taps.set(id, tap);
1030
- return tap;
1031
- }, _updateTap = (id, x, y) => {
1032
- const tap = _taps.get(id) || _registerTap(id);
1033
- tap.x = x;
1034
- tap.y = y;
1035
- }, _checkTapped = (tap) => tap && performance.now() - tap.ts <= 300, preventDefault = (ev) => ev.preventDefault();
950
+ const _getXY = (
951
+ /**
952
+ * @param {number} pageX
953
+ * @param {number} pageY
954
+ */
955
+ (pageX, pageY) => [
956
+ (pageX - _canvas.offsetLeft) / _scale,
957
+ (pageY - _canvas.offsetTop) / _scale
958
+ ]
959
+ ), _taps = /* @__PURE__ */ new Map(), _registerTap = (
960
+ /**
961
+ * @param {number} id
962
+ * @param {number} [x]
963
+ * @param {number} [y]
964
+ */
965
+ (id, x, y) => {
966
+ const tap = {
967
+ x,
968
+ y,
969
+ startX: x,
970
+ startY: y,
971
+ // timestamp
972
+ ts: performance.now()
973
+ };
974
+ _taps.set(id, tap);
975
+ return tap;
976
+ }
977
+ ), _updateTap = (
978
+ /**
979
+ * @param {number} id
980
+ * @param {number} x
981
+ * @param {number} y
982
+ */
983
+ (id, x, y) => {
984
+ const tap = _taps.get(id) || _registerTap(id);
985
+ tap.x = x;
986
+ tap.y = y;
987
+ }
988
+ ), _checkTapped = (
989
+ /**
990
+ * @param {{ts: number}} tap
991
+ */
992
+ (tap) => tap && performance.now() - tap.ts <= 300
993
+ ), preventDefault = (ev) => ev.preventDefault();
1036
994
  let _pressingMouse = false;
1037
995
  on(
1038
996
  _canvas,
@@ -1237,10 +1195,7 @@
1237
1195
  _canvas = document.querySelector(settings.canvas);
1238
1196
  }
1239
1197
  _canvas = _canvas || document.createElement("canvas");
1240
- DEV: assert(
1241
- _canvas && _canvas.tagName === "CANVAS",
1242
- "Invalid canvas element"
1243
- );
1198
+ DEV: assert(_canvas && _canvas.tagName === "CANVAS", "Invalid canvas element");
1244
1199
  instance.def("CANVAS", _canvas);
1245
1200
  _ctx = _canvas.getContext("2d");
1246
1201
  on(_canvas, "click", () => root.focus());
@@ -1273,10 +1228,7 @@
1273
1228
  _canvas.style.display = "block";
1274
1229
  _canvas.style.margin = "auto";
1275
1230
  }
1276
- _scale = math.min(
1277
- root.innerWidth / instance.W,
1278
- root.innerHeight / instance.H
1279
- );
1231
+ _scale = math.min(root.innerWidth / instance.W, root.innerHeight / instance.H);
1280
1232
  _scale = (settings.pixelart ? ~~_scale : _scale) || 1;
1281
1233
  _canvas.style.width = instance.W * _scale + "px";
1282
1234
  _canvas.style.height = instance.H * _scale + "px";