litecanvas 0.86.0 → 0.88.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.
package/dist/dist.dev.js CHANGED
@@ -31,12 +31,15 @@
31
31
  if (!condition) throw new Error(message);
32
32
  };
33
33
 
34
+ // version.js
35
+ var version = "0.88.0";
36
+
34
37
  // src/index.js
35
38
  function litecanvas(settings = {}) {
36
39
  const root = window, math = Math, TWO_PI = math.PI * 2, raf = requestAnimationFrame, _browserEventListeners = [], on = (elem, evt, callback) => {
37
40
  elem.addEventListener(evt, callback, false);
38
41
  _browserEventListeners.push(() => elem.removeEventListener(evt, callback, false));
39
- }, isNumber = Number.isFinite, zzfx = setupZzFX(root), defaults = {
42
+ }, beginPath = (c) => c.beginPath(), isNumber = Number.isFinite, zzfx = setupZzFX(root), defaults = {
40
43
  width: null,
41
44
  height: null,
42
45
  autoscale: true,
@@ -90,9 +93,9 @@
90
93
  * @tutorial https://gamedev.net/tutorials/programming/general-and-gameplay-programming/a-brief-introduction-to-lerp-r4954/
91
94
  */
92
95
  lerp: (start, end, t) => {
93
- DEV: assert(isNumber(start), "lerp: 1st param must be a number");
94
- DEV: assert(isNumber(end), "lerp: 2nd param must be a number");
95
- DEV: assert(isNumber(t), "lerp: 3rd param must be a number");
96
+ DEV: assert(isNumber(start), "[litecanvas] lerp() 1st param must be a number");
97
+ DEV: assert(isNumber(end), "[litecanvas] lerp() 2nd param must be a number");
98
+ DEV: assert(isNumber(t), "[litecanvas] lerp() 3rd param must be a number");
96
99
  return t * (end - start) + start;
97
100
  },
98
101
  /**
@@ -125,10 +128,10 @@
125
128
  * @returns {number} rounded number.
126
129
  */
127
130
  round: (n, precision = 0) => {
128
- DEV: assert(isNumber(n), "round: 1st param must be a number");
131
+ DEV: assert(isNumber(n), "[litecanvas] round() 1st param must be a number");
129
132
  DEV: assert(
130
133
  null == precision || isNumber(precision) && precision >= 0,
131
- "round: 2nd param must be a positive number or zero"
134
+ "[litecanvas] round() 2nd param must be a positive number or zero"
132
135
  );
133
136
  if (!precision) {
134
137
  return math.round(n);
@@ -145,10 +148,13 @@
145
148
  * @returns {number}
146
149
  */
147
150
  clamp: (value, min, max) => {
148
- DEV: assert(isNumber(value), "clamp: 1st param must be a number");
149
- DEV: assert(isNumber(min), "clamp: 2nd param must be a number");
150
- DEV: assert(isNumber(max), "clamp: 3rd param must be a number");
151
- DEV: assert(max > min, "clamp: the 2nd param must be less than the 3rd param");
151
+ DEV: assert(isNumber(value), "[litecanvas] clamp() 1st param must be a number");
152
+ DEV: assert(isNumber(min), "[litecanvas] clamp() 2nd param must be a number");
153
+ DEV: assert(isNumber(max), "[litecanvas] clamp() 3rd param must be a number");
154
+ DEV: assert(
155
+ max > min,
156
+ "[litecanvas] clamp() the 2nd param must be less than the 3rd param"
157
+ );
152
158
  if (value < min) return min;
153
159
  if (value > max) return max;
154
160
  return value;
@@ -162,10 +168,13 @@
162
168
  * @returns {number}
163
169
  */
164
170
  wrap: (value, min, max) => {
165
- DEV: assert(isNumber(value), "wrap: 1st param must be a number");
166
- DEV: assert(isNumber(min), "wrap: 2nd param must be a number");
167
- DEV: assert(isNumber(max), "wrap: 3rd param must be a number");
168
- DEV: assert(max > min, "wrap: the 2nd param must be less than the 3rd param");
171
+ DEV: assert(isNumber(value), "[litecanvas] wrap() 1st param must be a number");
172
+ DEV: assert(isNumber(min), "[litecanvas] wrap() 2nd param must be a number");
173
+ DEV: assert(isNumber(max), "[litecanvas] wrap() 3rd param must be a number");
174
+ DEV: assert(
175
+ max > min,
176
+ "[litecanvas] wrap() the 2nd param must be less than the 3rd param"
177
+ );
169
178
  return value - (max - min) * math.floor((value - min) / (max - min));
170
179
  },
171
180
  /**
@@ -180,12 +189,15 @@
180
189
  * @returns {number} the remapped number
181
190
  */
182
191
  map(value, start1, stop1, start2, stop2, withinBounds) {
183
- DEV: assert(isNumber(value), "map: 1st param must be a number");
184
- DEV: assert(isNumber(start1), "map: 2nd param must be a number");
185
- DEV: assert(isNumber(stop1), "map: 3rd param must be a number");
186
- DEV: assert(isNumber(start2), "map: 4th param must be a number");
187
- DEV: assert(isNumber(stop2), "map: 5th param must be a number");
188
- DEV: assert(stop1 !== start1, "map: the 2nd param must be different than the 3rd param");
192
+ DEV: assert(isNumber(value), "[litecanvas] map() 1st param must be a number");
193
+ DEV: assert(isNumber(start1), "[litecanvas] map() 2nd param must be a number");
194
+ DEV: assert(isNumber(stop1), "[litecanvas] map() 3rd param must be a number");
195
+ DEV: assert(isNumber(start2), "[litecanvas] map() 4th param must be a number");
196
+ DEV: assert(isNumber(stop2), "[litecanvas] map() 5th param must be a number");
197
+ DEV: assert(
198
+ stop1 !== start1,
199
+ "[litecanvas] map() the 2nd param must be different than the 3rd param"
200
+ );
189
201
  const result = (value - start1) / (stop1 - start1) * (stop2 - start2) + start2;
190
202
  return withinBounds ? instance.clamp(result, start2, stop2) : result;
191
203
  },
@@ -200,10 +212,13 @@
200
212
  * @returns {number} the normalized number.
201
213
  */
202
214
  norm: (value, start, stop) => {
203
- DEV: assert(isNumber(value), "norm: 1st param must be a number");
204
- DEV: assert(isNumber(start), "norm: 2nd param must be a number");
205
- DEV: assert(isNumber(stop), "norm: 3rd param must be a number");
206
- DEV: assert(start !== stop, "norm: the 2nd param must be different than the 3rd param");
215
+ DEV: assert(isNumber(value), "[litecanvas] norm() 1st param must be a number");
216
+ DEV: assert(isNumber(start), "[litecanvas] norm() 2nd param must be a number");
217
+ DEV: assert(isNumber(stop), "[litecanvas] norm() 3rd param must be a number");
218
+ DEV: assert(
219
+ start !== stop,
220
+ "[litecanvas] norm() the 2nd param must be different than the 3rd param"
221
+ );
207
222
  return instance.map(value, start, stop, 0, 1);
208
223
  },
209
224
  /**
@@ -215,12 +230,12 @@
215
230
  * @param {(n: number) => number} [fn] - the periodic function (which default to `Math.sin`)
216
231
  */
217
232
  wave: (from, to, t, fn = Math.sin) => {
218
- DEV: assert(isNumber(from), "wave: 1st param must be a number");
219
- DEV: assert(isNumber(to), "wave: 2nd param must be a number");
220
- DEV: assert(isNumber(t), "wave: 3rd param must be a number");
233
+ DEV: assert(isNumber(from), "[litecanvas] wave() 1st param must be a number");
234
+ DEV: assert(isNumber(to), "[litecanvas] wave() 2nd param must be a number");
235
+ DEV: assert(isNumber(t), "[litecanvas] wave() 3rd param must be a number");
221
236
  DEV: assert(
222
237
  "function" === typeof fn,
223
- "wave: 4rd param must be a function (n: number) => number"
238
+ "[litecanvas] wave() 4rd param must be a function (n: number) => number"
224
239
  );
225
240
  return from + (fn(t) + 1) / 2 * (to - from);
226
241
  },
@@ -234,9 +249,12 @@
234
249
  * @returns {number} the random number
235
250
  */
236
251
  rand: (min = 0, max = 1) => {
237
- DEV: assert(isNumber(min), "rand: 1st param must be a number");
238
- DEV: assert(isNumber(max), "rand: 2nd param must be a number");
239
- DEV: assert(max > min, "rand: the 1st param must be less than the 2nd param");
252
+ DEV: assert(isNumber(min), "[litecanvas] rand() 1st param must be a number");
253
+ DEV: assert(isNumber(max), "[litecanvas] rand() 2nd param must be a number");
254
+ DEV: assert(
255
+ max > min,
256
+ "[litecanvas] rand() the 1st param must be less than the 2nd param"
257
+ );
240
258
  const a = 1664525;
241
259
  const c = 1013904223;
242
260
  const m = 4294967296;
@@ -251,9 +269,12 @@
251
269
  * @returns {number} the random number
252
270
  */
253
271
  randi: (min = 0, max = 1) => {
254
- DEV: assert(isNumber(min), "randi: 1st param must be a number");
255
- DEV: assert(isNumber(max), "randi: 2nd param must be a number");
256
- DEV: assert(max > min, "randi: the 1st param must be less than the 2nd param");
272
+ DEV: assert(isNumber(min), "[litecanvas] randi() 1st param must be a number");
273
+ DEV: assert(isNumber(max), "[litecanvas] randi() 2nd param must be a number");
274
+ DEV: assert(
275
+ max > min,
276
+ "[litecanvas] randi() the 1st param must be less than the 2nd param"
277
+ );
257
278
  return math.floor(instance.rand(min, max + 1));
258
279
  },
259
280
  /**
@@ -266,7 +287,7 @@
266
287
  rseed(value) {
267
288
  DEV: assert(
268
289
  null == value || isNumber(value) && value >= 0,
269
- "rseed: 1st param must be a positive number or zero"
290
+ "[litecanvas] rseed() 1st param must be a positive number or zero"
270
291
  );
271
292
  _rngSeed = ~~value;
272
293
  },
@@ -279,7 +300,7 @@
279
300
  cls(color) {
280
301
  DEV: assert(
281
302
  null == color || isNumber(color) && color >= 0,
282
- "cls: 1st param must be a positive number or zero or undefined"
303
+ "[litecanvas] cls() 1st param must be a positive number or zero or undefined"
283
304
  );
284
305
  if (null == color) {
285
306
  _ctx.clearRect(0, 0, _ctx.canvas.width, _ctx.canvas.height);
@@ -300,22 +321,25 @@
300
321
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/roundRect
301
322
  */
302
323
  rect(x, y, width, height, color, radii) {
303
- DEV: assert(isNumber(x), "rect: 1st param must be a number");
304
- DEV: assert(isNumber(y), "rect: 2nd param must be a number");
305
- DEV: assert(isNumber(width) && width > 0, "rect: 3rd param must be a positive number");
324
+ DEV: assert(isNumber(x), "[litecanvas] rect() 1st param must be a number");
325
+ DEV: assert(isNumber(y), "[litecanvas] rect() 2nd param must be a number");
326
+ DEV: assert(
327
+ isNumber(width) && width > 0,
328
+ "[litecanvas] rect() 3rd param must be a positive number"
329
+ );
306
330
  DEV: assert(
307
331
  isNumber(height) && height >= 0,
308
- "rect: 4th param must be a positive number or zero"
332
+ "[litecanvas] rect() 4th param must be a positive number or zero"
309
333
  );
310
334
  DEV: assert(
311
335
  null == color || isNumber(color) && color >= 0,
312
- "rect: 5th param must be a positive number or zero"
336
+ "[litecanvas] rect() 5th param must be a positive number or zero"
313
337
  );
314
338
  DEV: assert(
315
339
  null == radii || isNumber(radii) || Array.isArray(radii) && radii.length >= 1,
316
- "rect: 6th param must be a number or array of numbers"
340
+ "[litecanvas] rect() 6th param must be a number or array of numbers"
317
341
  );
318
- _ctx.beginPath();
342
+ beginPath(_ctx);
319
343
  _ctx[radii ? "roundRect" : "rect"](
320
344
  ~~x - _outline_fix,
321
345
  ~~y - _outline_fix,
@@ -336,25 +360,25 @@
336
360
  * @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
337
361
  */
338
362
  rectfill(x, y, width, height, color, radii) {
339
- DEV: assert(isNumber(x), "rectfill: 1st param must be a number");
340
- DEV: assert(isNumber(y), "rectfill: 2nd param must be a number");
363
+ DEV: assert(isNumber(x), "[litecanvas] rectfill() 1st param must be a number");
364
+ DEV: assert(isNumber(y), "[litecanvas] rectfill() 2nd param must be a number");
341
365
  DEV: assert(
342
366
  isNumber(width) && width >= 0,
343
- "rectfill: 3rd param must be a positive number or zero"
367
+ "[litecanvas] rectfill() 3rd param must be a positive number or zero"
344
368
  );
345
369
  DEV: assert(
346
370
  isNumber(height) && height >= 0,
347
- "rectfill: 4th param must be a positive number or zero"
371
+ "[litecanvas] rectfill() 4th param must be a positive number or zero"
348
372
  );
349
373
  DEV: assert(
350
374
  null == color || isNumber(color) && color >= 0,
351
- "rectfill: 5th param must be a positive number or zero"
375
+ "[litecanvas] rectfill() 5th param must be a positive number or zero"
352
376
  );
353
377
  DEV: assert(
354
378
  null == radii || isNumber(radii) || Array.isArray(radii) && radii.length >= 1,
355
- "rectfill: 6th param must be a number or array of at least 2 numbers"
379
+ "[litecanvas] rectfill() 6th param must be a number or array of at least 2 numbers"
356
380
  );
357
- _ctx.beginPath();
381
+ beginPath(_ctx);
358
382
  _ctx[radii ? "roundRect" : "rect"](~~x, ~~y, ~~width, ~~height, radii);
359
383
  instance.fill(color);
360
384
  },
@@ -367,17 +391,17 @@
367
391
  * @param {number} [color=0] the color index
368
392
  */
369
393
  circ(x, y, radius, color) {
370
- DEV: assert(isNumber(x), "circ: 1st param must be a number");
371
- DEV: assert(isNumber(y), "circ: 2nd param must be a number");
394
+ DEV: assert(isNumber(x), "[litecanvas] circ() 1st param must be a number");
395
+ DEV: assert(isNumber(y), "[litecanvas] circ() 2nd param must be a number");
372
396
  DEV: assert(
373
397
  isNumber(radius) && radius >= 0,
374
- "circ: 3rd param must be a positive number or zero"
398
+ "[litecanvas] circ() 3rd param must be a positive number or zero"
375
399
  );
376
400
  DEV: assert(
377
401
  null == color || isNumber(color) && color >= 0,
378
- "circ: 4th param must be a positive number or zero"
402
+ "[litecanvas] circ() 4th param must be a positive number or zero"
379
403
  );
380
- _ctx.beginPath();
404
+ beginPath(_ctx);
381
405
  _ctx.arc(~~x, ~~y, ~~radius, 0, TWO_PI);
382
406
  instance.stroke(color);
383
407
  },
@@ -390,17 +414,17 @@
390
414
  * @param {number} [color=0] the color index
391
415
  */
392
416
  circfill(x, y, radius, color) {
393
- DEV: assert(isNumber(x), "circfill: 1st param must be a number");
394
- DEV: assert(isNumber(y), "circfill: 2nd param must be a number");
417
+ DEV: assert(isNumber(x), "[litecanvas] circfill() 1st param must be a number");
418
+ DEV: assert(isNumber(y), "[litecanvas] circfill() 2nd param must be a number");
395
419
  DEV: assert(
396
420
  isNumber(radius) && radius >= 0,
397
- "circfill: 3rd param must be a positive number or zero"
421
+ "[litecanvas] circfill() 3rd param must be a positive number or zero"
398
422
  );
399
423
  DEV: assert(
400
424
  null == color || isNumber(color) && color >= 0,
401
- "circfill: 4th param must be a positive number or zero"
425
+ "[litecanvas] circfill() 4th param must be a positive number or zero"
402
426
  );
403
- _ctx.beginPath();
427
+ beginPath(_ctx);
404
428
  _ctx.arc(~~x, ~~y, ~~radius, 0, TWO_PI);
405
429
  instance.fill(color);
406
430
  },
@@ -414,21 +438,21 @@
414
438
  * @param {number} [color=0] the color index
415
439
  */
416
440
  oval(x, y, radiusX, radiusY, color) {
417
- DEV: assert(isNumber(x), "oval: 1st param must be a number");
418
- DEV: assert(isNumber(y), "oval: 2nd param must be a number");
441
+ DEV: assert(isNumber(x), "[litecanvas] oval() 1st param must be a number");
442
+ DEV: assert(isNumber(y), "[litecanvas] oval() 2nd param must be a number");
419
443
  DEV: assert(
420
444
  isNumber(radiusX) && radiusX >= 0,
421
- "oval: 3rd param must be a positive number or zero"
445
+ "[litecanvas] oval() 3rd param must be a positive number or zero"
422
446
  );
423
447
  DEV: assert(
424
448
  isNumber(radiusY) && radiusY >= 0,
425
- "oval: 4th param must be a positive number or zero"
449
+ "[litecanvas] oval() 4th param must be a positive number or zero"
426
450
  );
427
451
  DEV: assert(
428
452
  null == color || isNumber(color) && color >= 0,
429
- "oval: 5th param must be a positive number or zero"
453
+ "[litecanvas] oval() 5th param must be a positive number or zero"
430
454
  );
431
- _ctx.beginPath();
455
+ beginPath(_ctx);
432
456
  _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
433
457
  instance.stroke(color);
434
458
  },
@@ -442,21 +466,21 @@
442
466
  * @param {number} [color=0] the color index
443
467
  */
444
468
  ovalfill(x, y, radiusX, radiusY, color) {
445
- DEV: assert(isNumber(x), "ovalfill: 1st param must be a number");
446
- DEV: assert(isNumber(y), "ovalfill: 2nd param must be a number");
469
+ DEV: assert(isNumber(x), "[litecanvas] ovalfill() 1st param must be a number");
470
+ DEV: assert(isNumber(y), "[litecanvas] ovalfill() 2nd param must be a number");
447
471
  DEV: assert(
448
472
  isNumber(radiusX) && radiusX >= 0,
449
- "ovalfill: 3rd param must be a positive number or zero"
473
+ "[litecanvas] ovalfill() 3rd param must be a positive number or zero"
450
474
  );
451
475
  DEV: assert(
452
476
  isNumber(radiusY) && radiusY >= 0,
453
- "ovalfill: 4th param must be a positive number or zero"
477
+ "[litecanvas] ovalfill() 4th param must be a positive number or zero"
454
478
  );
455
479
  DEV: assert(
456
480
  null == color || isNumber(color) && color >= 0,
457
- "ovalfill: 5th param must be a positive number or zero"
481
+ "[litecanvas] ovalfill() 5th param must be a positive number or zero"
458
482
  );
459
- _ctx.beginPath();
483
+ beginPath(_ctx);
460
484
  _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
461
485
  instance.fill(color);
462
486
  },
@@ -470,15 +494,21 @@
470
494
  * @param {number} [color=0] the color index
471
495
  */
472
496
  line(x1, y1, x2, y2, color) {
473
- DEV: assert(isNumber(x1), "line: 1st param must be a number");
474
- DEV: assert(isNumber(y1), "line: 2nd param must be a number");
475
- DEV: assert(isNumber(x2), "line: 3rd param must be a positive number or zero");
476
- DEV: assert(isNumber(y2), "line: 4th param must be a positive number or zero");
497
+ DEV: assert(isNumber(x1), "[litecanvas] line() 1st param must be a number");
498
+ DEV: assert(isNumber(y1), "[litecanvas] line() 2nd param must be a number");
499
+ DEV: assert(
500
+ isNumber(x2),
501
+ "[litecanvas] line() 3rd param must be a positive number or zero"
502
+ );
503
+ DEV: assert(
504
+ isNumber(y2),
505
+ "[litecanvas] line() 4th param must be a positive number or zero"
506
+ );
477
507
  DEV: assert(
478
508
  null == color || isNumber(color) && color >= 0,
479
- "line: 5th param must be a positive number or zero"
509
+ "[litecanvas] line() 5th param must be a positive number or zero"
480
510
  );
481
- _ctx.beginPath();
511
+ beginPath(_ctx);
482
512
  let xfix = _outline_fix !== 0 && ~~x1 === ~~x2 ? 0.5 : 0;
483
513
  let yfix = _outline_fix !== 0 && ~~y1 === ~~y2 ? 0.5 : 0;
484
514
  _ctx.moveTo(~~x1 + xfix, ~~y1 + yfix);
@@ -494,7 +524,7 @@
494
524
  linewidth(value) {
495
525
  DEV: assert(
496
526
  isNumber(value) && ~~value > 0,
497
- "linewidth: 1st param must be a positive number"
527
+ "[litecanvas] linewidth() 1st param must be a positive number"
498
528
  );
499
529
  _ctx.lineWidth = ~~value;
500
530
  _outline_fix = 0 === ~~value % 2 ? 0 : 0.5;
@@ -510,9 +540,9 @@
510
540
  linedash(segments, offset = 0) {
511
541
  DEV: assert(
512
542
  Array.isArray(segments) && segments.length > 0,
513
- "linedash: 1st param must be an array of numbers"
543
+ "[litecanvas] linedash() 1st param must be an array of numbers"
514
544
  );
515
- DEV: assert(isNumber(offset), "linedash: 2nd param must be a number");
545
+ DEV: assert(isNumber(offset), "[litecanvas] linedash() 2nd param must be a number");
516
546
  _ctx.setLineDash(segments);
517
547
  _ctx.lineDashOffset = offset;
518
548
  },
@@ -527,13 +557,16 @@
527
557
  * @param {string} [fontStyle] can be "normal" (default), "italic" and/or "bold".
528
558
  */
529
559
  text(x, y, message, color = 3, fontStyle = "normal") {
530
- DEV: assert(isNumber(x), "text: 1st param must be a number");
531
- DEV: assert(isNumber(y), "text: 2nd param must be a number");
560
+ DEV: assert(isNumber(x), "[litecanvas] text() 1st param must be a number");
561
+ DEV: assert(isNumber(y), "[litecanvas] text() 2nd param must be a number");
532
562
  DEV: assert(
533
563
  null == color || isNumber(color) && color >= 0,
534
- "text: 4th param must be a positive number or zero"
564
+ "[litecanvas] text() 4th param must be a positive number or zero"
565
+ );
566
+ DEV: assert(
567
+ "string" === typeof fontStyle,
568
+ "[litecanvas] text() 5th param must be a string"
535
569
  );
536
- DEV: assert("string" === typeof fontStyle, "text: 5th param must be a string");
537
570
  _ctx.font = `${fontStyle} ${_fontSize}px ${_fontFamily}`;
538
571
  _ctx.fillStyle = _colors[~~color % _colors.length];
539
572
  _ctx.fillText(message, ~~x, ~~y);
@@ -544,7 +577,10 @@
544
577
  * @param {string} family
545
578
  */
546
579
  textfont(family) {
547
- DEV: assert("string" === typeof family, "textfont: 1st param must be a string");
580
+ DEV: assert(
581
+ "string" === typeof family,
582
+ "[litecanvas] textfont() 1st param must be a string"
583
+ );
548
584
  _fontFamily = family;
549
585
  },
550
586
  /**
@@ -553,7 +589,7 @@
553
589
  * @param {number} size
554
590
  */
555
591
  textsize(size) {
556
- DEV: assert(isNumber(size), "textsize: 1st param must be a number");
592
+ DEV: assert(isNumber(size), "[litecanvas] textsize() 1st param must be a number");
557
593
  _fontSize = size;
558
594
  },
559
595
  /**
@@ -567,13 +603,13 @@
567
603
  textalign(align, baseline) {
568
604
  DEV: assert(
569
605
  null == align || ["left", "right", "center", "start", "end"].includes(align),
570
- "textalign: 1st param must be null or one of the following strings: center, left, right, start or end."
606
+ "[litecanvas] textalign() 1st param must be null or one of the following strings: center, left, right, start or end."
571
607
  );
572
608
  DEV: assert(
573
609
  null == baseline || ["top", "bottom", "middle", "hanging", "alphabetic", "ideographic"].includes(
574
610
  baseline
575
611
  ),
576
- "textalign: 2nd param must be null or one of the following strings: middle, top, bottom, hanging, alphabetic or ideographic."
612
+ "[litecanvas] textalign() 2nd param must be null or one of the following strings: middle, top, bottom, hanging, alphabetic or ideographic."
577
613
  );
578
614
  if (align) _ctx.textAlign = align;
579
615
  if (baseline) _ctx.textBaseline = baseline;
@@ -587,8 +623,8 @@
587
623
  * @param {OffscreenCanvas|HTMLImageElement|HTMLCanvasElement} source
588
624
  */
589
625
  image(x, y, source) {
590
- DEV: assert(isNumber(x), "image: 1st param must be a number");
591
- DEV: assert(isNumber(y), "image: 2nd param must be a number");
626
+ DEV: assert(isNumber(x), "[litecanvas] image() 1st param must be a number");
627
+ DEV: assert(isNumber(y), "[litecanvas] image() 2nd param must be a number");
592
628
  _ctx.drawImage(source, ~~x, ~~y);
593
629
  },
594
630
  /**
@@ -604,22 +640,25 @@
604
640
  * @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
605
641
  */
606
642
  paint(width, height, drawing, options = {}) {
607
- DEV: assert(isNumber(width) && width >= 1, "paint: 1st param must be a positive number");
643
+ DEV: assert(
644
+ isNumber(width) && width >= 1,
645
+ "[litecanvas] paint() 1st param must be a positive number"
646
+ );
608
647
  DEV: assert(
609
648
  isNumber(height) && height >= 1,
610
- "paint: 2nd param must be a positive number"
649
+ "[litecanvas] paint() 2nd param must be a positive number"
611
650
  );
612
651
  DEV: assert(
613
652
  "function" === typeof drawing || Array.isArray(drawing),
614
- "paint: 3rd param must be a function or array"
653
+ "[litecanvas] paint() 3rd param must be a function or array"
615
654
  );
616
655
  DEV: assert(
617
656
  options && null == options.scale || isNumber(options.scale),
618
- "paint: 4th param (options.scale) must be a number"
657
+ "[litecanvas] paint() 4th param (options.scale) must be a number"
619
658
  );
620
659
  DEV: assert(
621
660
  options && null == options.canvas || options.canvas instanceof OffscreenCanvas,
622
- "paint: 4th param (options.canvas) must be an OffscreenCanvas"
661
+ "[litecanvas] paint() 4th param (options.canvas) must be an OffscreenCanvas"
623
662
  );
624
663
  const canvas = options.canvas || new OffscreenCanvas(1, 1), scale = options.scale || 1, contextOriginal = _ctx;
625
664
  canvas.width = width * scale;
@@ -678,8 +717,8 @@
678
717
  * @param {number} y
679
718
  */
680
719
  translate: (x, y) => {
681
- DEV: assert(isNumber(x), "translate: 1st param must be a number");
682
- DEV: assert(isNumber(y), "translate: 2nd param must be a number");
720
+ DEV: assert(isNumber(x), "[litecanvas] translate() 1st param must be a number");
721
+ DEV: assert(isNumber(y), "[litecanvas] translate() 2nd param must be a number");
683
722
  return _ctx.translate(~~x, ~~y);
684
723
  },
685
724
  /**
@@ -689,8 +728,8 @@
689
728
  * @param {number} [y]
690
729
  */
691
730
  scale: (x, y) => {
692
- DEV: assert(isNumber(x), "scale: 1st param must be a number");
693
- DEV: assert(null == y || isNumber(y), "scale: 2nd param must be a number");
731
+ DEV: assert(isNumber(x), "[litecanvas] scale() 1st param must be a number");
732
+ DEV: assert(null == y || isNumber(y), "[litecanvas] scale() 2nd param must be a number");
694
733
  return _ctx.scale(x, y || x);
695
734
  },
696
735
  /**
@@ -699,7 +738,7 @@
699
738
  * @param {number} radians
700
739
  */
701
740
  rotate: (radians) => {
702
- DEV: assert(isNumber(radians), "rotate: 1st param must be a number");
741
+ DEV: assert(isNumber(radians), "[litecanvas] rotate() 1st param must be a number");
703
742
  return _ctx.rotate(radians);
704
743
  },
705
744
  /**
@@ -709,80 +748,49 @@
709
748
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalAlpha
710
749
  */
711
750
  alpha(value) {
712
- DEV: assert(isNumber(value), "alpha: 1st param must be a number");
751
+ DEV: assert(isNumber(value), "[litecanvas] alpha() 1st param must be a number");
713
752
  _ctx.globalAlpha = instance.clamp(value, 0, 1);
714
753
  },
715
754
  /**
716
- * Returns a newly instantiated Path2D object, optionally with another
717
- * path as an argument (creates a copy), or optionally with a string
718
- * consisting of SVG path data.
719
- *
720
- * @param {Path2D|string} [arg]
721
- * @returns Path2D
722
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D
723
- */
724
- path: (arg) => {
725
- DEV: assert(
726
- null == arg || "string" === typeof arg || arg instanceof Path2D,
727
- "path: 1st param must be a string or a Path2D instance"
728
- );
729
- return new Path2D(arg);
730
- },
731
- /**
732
- * Fills the current or given path with a given color.
755
+ * Fills the current path with a given color.
733
756
  *
734
757
  * @param {number} [color=0]
735
- * @param {Path2D} [path]
736
758
  */
737
- fill(color, path) {
759
+ fill(color) {
738
760
  DEV: assert(
739
761
  null == color || isNumber(color) && color >= 0,
740
- "fill: 1st param must be a positive number or zero"
741
- );
742
- DEV: assert(
743
- null == path || path instanceof Path2D,
744
- "fill: 2nd param must be a Path2D instance"
762
+ "[litecanvas] fill() 1st param must be a positive number or zero"
745
763
  );
746
764
  _ctx.fillStyle = _colors[~~color % _colors.length];
747
- if (path) {
748
- _ctx.fill(path);
749
- } else {
750
- _ctx.fill();
751
- }
765
+ _ctx.fill();
752
766
  },
753
767
  /**
754
- * Outlines the current or given path with a given color.
768
+ * Outlines the current path with a given color.
755
769
  *
756
770
  * @param {number} [color=0]
757
- * @param {Path2D} [path]
758
771
  */
759
- stroke(color, path) {
772
+ stroke(color) {
760
773
  DEV: assert(
761
774
  null == color || isNumber(color) && color >= 0,
762
- "stroke: 1st param must be a positive number or zero"
763
- );
764
- DEV: assert(
765
- null == path || path instanceof Path2D,
766
- "stroke: 2nd param must be a Path2D instance"
775
+ "[litecanvas] stroke() 1st param must be a positive number or zero"
767
776
  );
768
777
  _ctx.strokeStyle = _colors[~~color % _colors.length];
769
- if (path) {
770
- _ctx.stroke(path);
771
- } else {
772
- _ctx.stroke();
773
- }
778
+ _ctx.stroke();
774
779
  },
775
780
  /**
776
- * Turn given path into a clipping region.
781
+ * Turns a path (in the callback) into the current clipping region.
777
782
  *
778
- * Note: always call `push()` before and `pop()` after.
779
- *
780
- * @param {Path2D} path
783
+ * @param {clipCallback} callback
781
784
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip
782
785
  */
783
- clip(path) {
784
- DEV: assert(path instanceof Path2D, "clip: 1st param must be a Path2D instance");
785
- _ctx.clip(path);
786
+ clip(callback) {
787
+ DEV: assert(
788
+ "function" === typeof callback,
789
+ "[litecanvas] clip() 1st param must be a function"
790
+ );
791
+ beginPath(_ctx);
792
+ callback(_ctx);
793
+ _ctx.clip();
786
794
  },
787
795
  /** SOUND API */
788
796
  /**
@@ -799,10 +807,10 @@
799
807
  sfx(zzfxParams, pitchSlide = 0, volumeFactor = 1) {
800
808
  DEV: assert(
801
809
  null == zzfxParams || Array.isArray(zzfxParams),
802
- "sfx: 1st param must be an array"
810
+ "[litecanvas] sfx() 1st param must be an array"
803
811
  );
804
- DEV: assert(isNumber(pitchSlide), "sfx: 2nd param must be a number");
805
- DEV: assert(isNumber(volumeFactor), "sfx: 3rd param must be a number");
812
+ DEV: assert(isNumber(pitchSlide), "[litecanvas] sfx() 2nd param must be a number");
813
+ DEV: assert(isNumber(volumeFactor), "[litecanvas] sfx() 3rd param must be a number");
806
814
  if (
807
815
  // @ts-ignore
808
816
  root.zzfxV <= 0 || navigator.userActivation && !navigator.userActivation.hasBeenActive
@@ -825,7 +833,7 @@
825
833
  * @param {number} value
826
834
  */
827
835
  volume(value) {
828
- DEV: assert(isNumber(value), "volume: 1st param must be a number");
836
+ DEV: assert(isNumber(value), "[litecanvas] volume() 1st param must be a number");
829
837
  root.zzfxV = value;
830
838
  },
831
839
  /** PLUGINS API */
@@ -841,8 +849,14 @@
841
849
  * @param {pluginCallback} callback
842
850
  */
843
851
  use(callback, config = {}) {
844
- DEV: assert("function" === typeof callback, "use: 1st param must be a function");
845
- DEV: assert("object" === typeof config, "use: 2nd param must be an object");
852
+ DEV: assert(
853
+ "function" === typeof callback,
854
+ "[litecanvas] use() 1st param must be a function"
855
+ );
856
+ DEV: assert(
857
+ "object" === typeof config,
858
+ "[litecanvas] use() 2nd param must be an object"
859
+ );
846
860
  if (_initialized) {
847
861
  loadPlugin(callback, config);
848
862
  } else {
@@ -857,8 +871,14 @@
857
871
  * @returns {Function} a function to remove the listener
858
872
  */
859
873
  listen(eventName, callback) {
860
- DEV: assert("string" === typeof eventName, "listen: 1st param must be a string");
861
- DEV: assert("function" === typeof callback, "listen: 2nd param must be a function");
874
+ DEV: assert(
875
+ "string" === typeof eventName,
876
+ "[litecanvas] listen() 1st param must be a string"
877
+ );
878
+ DEV: assert(
879
+ "function" === typeof callback,
880
+ "[litecanvas] listen() 2nd param must be a function"
881
+ );
862
882
  eventName = eventName.toLowerCase();
863
883
  _eventListeners[eventName] = _eventListeners[eventName] || /* @__PURE__ */ new Set();
864
884
  _eventListeners[eventName].add(callback);
@@ -874,7 +894,10 @@
874
894
  * @param {*} [arg4] any data to be passed over the listeners
875
895
  */
876
896
  emit(eventName, arg1, arg2, arg3, arg4) {
877
- DEV: assert("string" === typeof eventName, "emit: 1st param must be a string");
897
+ DEV: assert(
898
+ "string" === typeof eventName,
899
+ "[litecanvas] emit() 1st param must be a string"
900
+ );
878
901
  if (_initialized) {
879
902
  eventName = eventName.toLowerCase();
880
903
  triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
@@ -890,7 +913,7 @@
890
913
  pal(colors = defaultPalette) {
891
914
  DEV: assert(
892
915
  Array.isArray(colors) && colors.length > 0,
893
- "pal: 1st param must be a array of strings"
916
+ "[litecanvas] pal() 1st param must be a array of strings"
894
917
  );
895
918
  _colors = colors;
896
919
  },
@@ -901,7 +924,7 @@
901
924
  * @param {*} value
902
925
  */
903
926
  def(key, value) {
904
- DEV: assert("string" === typeof key, "def: 1st param must be a string");
927
+ DEV: assert("string" === typeof key, "[litecanvas] def() 1st param must be a string");
905
928
  DEV: if (null == value) {
906
929
  console.warn(`def: key "${key}" was defined as ${value} but now is null`);
907
930
  }
@@ -920,7 +943,7 @@
920
943
  timescale(value) {
921
944
  DEV: assert(
922
945
  isNumber(value) && value >= 0,
923
- "timescale: 1st param must be a positive number or zero"
946
+ "[litecanvas] timescale() 1st param must be a positive number or zero"
924
947
  );
925
948
  _timeScale = value;
926
949
  },
@@ -932,7 +955,7 @@
932
955
  framerate(value) {
933
956
  DEV: assert(
934
957
  isNumber(value) && value >= 1,
935
- "framerate: 1st param must be a positive number"
958
+ "[litecanvas] framerate() 1st param must be a positive number"
936
959
  );
937
960
  _deltaTime = 1 / ~~value;
938
961
  },
@@ -943,14 +966,14 @@
943
966
  * @returns {any}
944
967
  */
945
968
  stat(n) {
946
- DEV: assert(isNumber(n) && n >= 0, "stat: 1st param must be a number");
969
+ DEV: assert(isNumber(n) && n >= 0, "[litecanvas] stat() 1st param must be a number");
947
970
  const list = [
948
971
  // 0
949
972
  settings,
950
973
  // 1
951
974
  _initialized,
952
975
  // 2
953
- _rafid,
976
+ _deltaTime,
954
977
  // 3
955
978
  _scale,
956
979
  // 4
@@ -979,8 +1002,7 @@
979
1002
  * Stops the litecanvas instance and remove all event listeners.
980
1003
  */
981
1004
  quit() {
982
- cancelAnimationFrame(_rafid);
983
- _rafid = 0;
1005
+ instance.pause();
984
1006
  instance.emit("quit");
985
1007
  _eventListeners = {};
986
1008
  for (const removeListener of _browserEventListeners) {
@@ -993,6 +1015,29 @@
993
1015
  delete root.ENGINE;
994
1016
  }
995
1017
  _initialized = false;
1018
+ },
1019
+ /**
1020
+ * Pauses the engine loop (update & draw).
1021
+ */
1022
+ pause() {
1023
+ cancelAnimationFrame(_rafid);
1024
+ _rafid = 0;
1025
+ },
1026
+ /**
1027
+ * Resumes (if paused) the engine loop.
1028
+ */
1029
+ resume() {
1030
+ if (!_rafid && _initialized) {
1031
+ _rafid = raf(drawFrame);
1032
+ }
1033
+ },
1034
+ /**
1035
+ * Returns `true` if the engine loop is paused.
1036
+ *
1037
+ * @returns {boolean}
1038
+ */
1039
+ paused() {
1040
+ return !_rafid;
996
1041
  }
997
1042
  };
998
1043
  for (const k of _mathFunctions.split(",")) {
@@ -1001,6 +1046,9 @@
1001
1046
  function init() {
1002
1047
  const source = settings.loop ? settings.loop : root;
1003
1048
  for (const event of _coreEvents.split(",")) {
1049
+ DEV: if (root === source && source[event]) {
1050
+ console.info(`[litecanvas] using window.${event}()`);
1051
+ }
1004
1052
  if (source[event]) instance.listen(event, source[event]);
1005
1053
  }
1006
1054
  for (const [callback, config] of _plugins) {
@@ -1197,7 +1245,7 @@
1197
1245
  (key) => {
1198
1246
  DEV: assert(
1199
1247
  null == key || "string" === typeof key,
1200
- "iskeydown: 1st param must be a string or undefined"
1248
+ "[litecanvas] iskeydown() 1st param must be a string or undefined"
1201
1249
  );
1202
1250
  return keyCheck(_keysDown, key);
1203
1251
  }
@@ -1214,7 +1262,7 @@
1214
1262
  (key) => {
1215
1263
  DEV: assert(
1216
1264
  null == key || "string" === typeof key,
1217
- "iskeypressed: 1st param must be a string or undefined"
1265
+ "[litecanvas] iskeypressed() 1st param must be a string or undefined"
1218
1266
  );
1219
1267
  return keyCheck(_keysPress, key);
1220
1268
  }
@@ -1222,42 +1270,47 @@
1222
1270
  }
1223
1271
  _initialized = true;
1224
1272
  instance.emit("init", instance);
1273
+ instance.textalign("start", "top");
1225
1274
  _lastFrameTime = performance.now();
1226
- _rafid = raf(drawFrame);
1275
+ instance.resume();
1227
1276
  }
1228
1277
  function drawFrame(now) {
1278
+ if (!settings.animate) {
1279
+ return instance.emit("draw");
1280
+ }
1229
1281
  let updated = 0;
1230
- if (settings.animate) {
1231
- _accumulated += math.min(0.1, (now - _lastFrameTime) / 1e3);
1232
- _lastFrameTime = now;
1282
+ let frameTime = (now - _lastFrameTime) / 1e3;
1283
+ _lastFrameTime = now;
1284
+ if (frameTime < 0.1) {
1285
+ _accumulated += frameTime;
1233
1286
  while (_accumulated >= _deltaTime) {
1234
1287
  updated++;
1235
1288
  instance.emit("update", _deltaTime * _timeScale, updated);
1236
1289
  instance.def("T", instance.T + _deltaTime * _timeScale);
1237
1290
  _accumulated -= _deltaTime;
1238
1291
  }
1239
- if (_rafid) {
1240
- _rafid = raf(drawFrame);
1241
- }
1242
- } else {
1243
- updated = 1;
1244
1292
  }
1245
1293
  if (updated) {
1246
- instance.textalign("start", "top");
1247
1294
  instance.emit("draw");
1248
1295
  }
1296
+ if (_rafid) {
1297
+ _rafid = raf(drawFrame);
1298
+ }
1249
1299
  }
1250
1300
  function setupCanvas() {
1251
1301
  if ("string" === typeof settings.canvas) {
1252
1302
  _canvas = document.querySelector(settings.canvas);
1253
- DEV: assert(null != _canvas, `Litecanvas' option "canvas" is an invalid CSS selector`);
1303
+ DEV: assert(
1304
+ null != _canvas,
1305
+ '[litecanvas] litecanvas() option "canvas" is an invalid CSS selector'
1306
+ );
1254
1307
  } else {
1255
1308
  _canvas = settings.canvas;
1256
1309
  }
1257
1310
  _canvas = _canvas || document.createElement("canvas");
1258
1311
  DEV: assert(
1259
1312
  "CANVAS" === _canvas.tagName,
1260
- `Litecanvas' option "canvas" should be a canvas element or string (CSS selector)`
1313
+ '[litecanvas] litecanvas() option "canvas" should be a canvas element or string (CSS selector)'
1261
1314
  );
1262
1315
  _ctx = _canvas.getContext("2d");
1263
1316
  on(_canvas, "click", () => root.focus());
@@ -1270,15 +1323,15 @@
1270
1323
  function resizeCanvas() {
1271
1324
  DEV: assert(
1272
1325
  null == settings.width || isNumber(settings.width) && settings.width > 0,
1273
- `Litecanvas' option "width" should be a positive number when defined`
1326
+ '[litecanvas] litecanvas() option "width" should be a positive number when defined'
1274
1327
  );
1275
1328
  DEV: assert(
1276
1329
  null == settings.height || isNumber(settings.height) && settings.height > 0,
1277
- `Litecanvas' option "height" should be a positive number when defined`
1330
+ '[litecanvas] litecanvas() option "height" should be a positive number when defined'
1278
1331
  );
1279
1332
  DEV: assert(
1280
1333
  null == settings.height || settings.width > 0 && settings.height > 0,
1281
- `Litecanvas' option "width" is required when the option "height" is defined`
1334
+ '[litecanvas] litecanvas() option "width" is required when the option "height" is defined'
1282
1335
  );
1283
1336
  const width = settings.width || root.innerWidth, height = settings.height || settings.width || root.innerHeight;
1284
1337
  instance.def("W", width);
@@ -1315,7 +1368,7 @@
1315
1368
  const pluginData = callback(instance, config);
1316
1369
  DEV: assert(
1317
1370
  null == pluginData || "object" === typeof pluginData,
1318
- "Litecanvas plugins should return an object or nothing"
1371
+ "[litecanvas] litecanvas() plugins should return an object or nothing"
1319
1372
  );
1320
1373
  for (const key in pluginData) {
1321
1374
  instance.def(key, pluginData[key]);
@@ -1323,11 +1376,13 @@
1323
1376
  }
1324
1377
  if (settings.global) {
1325
1378
  if (root.ENGINE) {
1326
- throw new Error("two global litecanvas detected");
1379
+ throw new Error("only one global litecanvas is allowed");
1327
1380
  }
1328
1381
  Object.assign(root, instance);
1329
1382
  root.ENGINE = instance;
1330
1383
  }
1384
+ DEV: console.info(`[litecanvas] version ${version} started`);
1385
+ DEV: console.debug(`[litecanvas] litecanvas() options =`, settings);
1331
1386
  setupCanvas();
1332
1387
  if ("loading" === document.readyState) {
1333
1388
  on(root, "DOMContentLoaded", () => raf(init));