@litecanvas/utils 0.24.0 → 0.24.2

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/noise.js CHANGED
@@ -19,6 +19,974 @@
19
19
  __export(noise_exports, {
20
20
  Noise: () => Noise
21
21
  });
22
+
23
+ // node_modules/litecanvas/src/zzfx.js
24
+ var zzfxX = /* @__PURE__ */ new AudioContext();
25
+ var zzfx = (p = 1, k = 0.05, b = 220, e = 0, r = 0, t = 0.1, q = 0, D = 1, u = 0, y = 0, v = 0, z = 0, l = 0, E = 0, A = 0, F = 0, c = 0, w = 1, m = 0, B = 0, N = 0) => {
26
+ let M = Math, d = 2 * M.PI, R = 44100, G = u *= 500 * d / R / R, C = b *= (1 - k + 2 * k * M.random(k = [])) * d / R, g = 0, H = 0, a = 0, n = 1, I = 0, J = 0, f = 0, h = N < 0 ? -1 : 1, x = d * h * N * 2 / R, L = M.cos(x), Z = M.sin, K = Z(x) / 4, O = 1 + K, X = -2 * L / O, Y = (1 - K) / O, P = (1 + h * L) / 2 / O, Q = -(h + L) / O, S = P, T = 0, U = 0, V = 0, W = 0;
27
+ e = R * e + 9;
28
+ m *= R;
29
+ r *= R;
30
+ t *= R;
31
+ c *= R;
32
+ y *= 500 * d / R ** 3;
33
+ A *= d / R;
34
+ v *= d / R;
35
+ z *= R;
36
+ l = R * l | 0;
37
+ p *= 0.3 * (globalThis.zzfxV || 1);
38
+ for (h = e + m + r + t + c | 0; a < h; k[a++] = f * p)
39
+ ++J % (100 * F | 0) || (f = q ? 1 < q ? 2 < q ? 3 < q ? Z(g * g) : M.max(M.min(M.tan(g), 1), -1) : 1 - (2 * g / d % 2 + 2) % 2 : 1 - 4 * M.abs(M.round(g / d) - g / d) : Z(g), f = (l ? 1 - B + B * Z(d * a / l) : 1) * (f < 0 ? -1 : 1) * M.abs(f) ** D * (a < e ? a / e : a < e + m ? 1 - (a - e) / m * (1 - w) : a < e + m + r ? w : a < h - c ? (h - a - c) / t * w : 0), f = c ? f / 2 + (c > a ? 0 : (a < h - c ? 1 : (h - a) / c) * k[a - c | 0] / 2 / p) : f, N ? f = W = S * T + Q * (T = U) + P * (U = f) - Y * V - X * (V = W) : 0), x = (b += u += y) * M.cos(A * H++), g += x + x * E * Z(a ** 5), n && ++n > z && (b += v, C += v, n = 0), !l || ++I % l || (b = C, u = G, n = n || 1);
40
+ p = zzfxX.createBuffer(1, h, R);
41
+ p.getChannelData(0).set(k);
42
+ b = zzfxX.createBufferSource();
43
+ b.buffer = p;
44
+ b.connect(zzfxX.destination);
45
+ b.start();
46
+ };
47
+
48
+ // node_modules/litecanvas/src/palette.js
49
+ var colors = [
50
+ "#111",
51
+ "#6a7799",
52
+ "#aec2c2",
53
+ "#FFF1E8",
54
+ "#e83b3b",
55
+ "#fabc20",
56
+ "#155fd9",
57
+ "#3cbcfc",
58
+ "#327345",
59
+ "#63c64d",
60
+ "#6c2c1f",
61
+ "#ac7c00"
62
+ ];
63
+
64
+ // node_modules/litecanvas/src/index.js
65
+ globalThis.litecanvas = litecanvas;
66
+ function litecanvas(settings = {}) {
67
+ const root = globalThis, PI = Math.PI, TWO_PI = PI * 2, raf = requestAnimationFrame, _browserEventListeners = [], on = (elem, evt, callback) => {
68
+ elem.addEventListener(evt, callback, false);
69
+ _browserEventListeners.push(
70
+ () => elem.removeEventListener(evt, callback, false)
71
+ );
72
+ }, defaults = {
73
+ fps: 60,
74
+ fullscreen: true,
75
+ width: null,
76
+ height: null,
77
+ autoscale: true,
78
+ pixelart: false,
79
+ antialias: false,
80
+ canvas: null,
81
+ global: true,
82
+ loop: null,
83
+ pauseOnBlur: true,
84
+ tapEvents: true,
85
+ keyboardEvents: true,
86
+ animate: true
87
+ };
88
+ settings = Object.assign(defaults, settings);
89
+ let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _fullscreen = settings.fullscreen, _autoscale = settings.autoscale, _animated = settings.animate, _scale = 1, _ctx, _timeScale = 1, _lastFrame, _step, _stepMs, _accumulated = 0, _focused = true, _fontFamily = "sans-serif", _fontStyle = "", _fontSize = 32, _rng_seed = Date.now(), _global = settings.global, _events = {
90
+ init: null,
91
+ update: null,
92
+ draw: null,
93
+ resized: null,
94
+ tap: null,
95
+ untap: null,
96
+ tapping: null,
97
+ tapped: null
98
+ }, _helpers = {
99
+ settings: Object.assign({}, settings),
100
+ colors
101
+ };
102
+ const instance = {
103
+ /** @type {number} */
104
+ WIDTH: settings.width,
105
+ /** @type {number} */
106
+ HEIGHT: settings.height || settings.width,
107
+ /** @type {HTMLCanvasElement} */
108
+ CANVAS: null,
109
+ /** @type {number} */
110
+ ELAPSED: 0,
111
+ /** @type {number} */
112
+ CENTERX: 0,
113
+ /** @type {number} */
114
+ CENTERY: 0,
115
+ /** @type {number} */
116
+ MOUSEX: -1,
117
+ /** @type {number} */
118
+ MOUSEY: -1,
119
+ /** @type {number[]} */
120
+ DEFAULT_SFX: [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
121
+ /** MATH API */
122
+ /**
123
+ * The value of the mathematical constant PI (π).
124
+ * Approximately 3.14159
125
+ *
126
+ * @type {number}
127
+ */
128
+ PI,
129
+ /**
130
+ * Twice the value of the mathematical constant PI (π).
131
+ * Approximately 6.28318
132
+ *
133
+ * Note: TWO_PI radians equals 360°, PI radians equals 180°,
134
+ * HALF_PI radians equals 90°, and HALF_PI/2 radians equals 45°.
135
+ *
136
+ * @type {number}
137
+ */
138
+ TWO_PI,
139
+ /**
140
+ * Half the value of the mathematical constant PI (π).
141
+ * Approximately 1.57079
142
+ *
143
+ * @type {number}
144
+ */
145
+ HALF_PI: PI * 0.5,
146
+ /**
147
+ * Calculates a linear (interpolation) value over t%.
148
+ *
149
+ * @param {number} start
150
+ * @param {number} end
151
+ * @param {number} t The progress in percentage, where 0 = 0% and 1 = 100%.
152
+ * @returns {number} The unterpolated value
153
+ * @tutorial https://gamedev.net/tutorials/programming/general-and-gameplay-programming/a-brief-introduction-to-lerp-r4954/
154
+ */
155
+ lerp: (start, end, t) => start + t * (end - start),
156
+ /**
157
+ * Convert degrees to radians
158
+ *
159
+ * @param {number} degs
160
+ * @returns {number} the value in radians
161
+ */
162
+ deg2rad: (degs) => PI / 180 * degs,
163
+ /**
164
+ * Convert radians to degrees
165
+ *
166
+ * @param {number} rads
167
+ * @returns {number} the value in degrees
168
+ */
169
+ rad2deg: (rads) => 180 / PI * rads,
170
+ /**
171
+ * Constrains a number between `min` and `max`.
172
+ *
173
+ * @param {number} value
174
+ * @param {number} min
175
+ * @param {number} max
176
+ * @returns {number}
177
+ */
178
+ clamp: (value, min, max) => {
179
+ if (value < min) return min;
180
+ if (value > max) return max;
181
+ return value;
182
+ },
183
+ /**
184
+ * Wraps a number between `min` (inclusive) and `max` (exclusive).
185
+ *
186
+ * @param {number} value
187
+ * @param {number} min
188
+ * @param {number} max
189
+ * @returns {number}
190
+ */
191
+ wrap: (value, min, max) => value - (max - min) * Math.floor((value - min) / (max - min)),
192
+ /**
193
+ * Re-maps a number from one range to another.
194
+ *
195
+ * @param {number} value the value to be remapped.
196
+ * @param {number} min1 lower bound of the value's current range.
197
+ * @param {number} max1 upper bound of the value's current range.
198
+ * @param {number} min2 lower bound of the value's target range.
199
+ * @param {number} max2 upper bound of the value's target range.
200
+ * @param {boolean} [withinBounds=false] constrain the value to the newly mapped range
201
+ * @returns {number} the remapped number
202
+ */
203
+ map(value, min1, max1, min2, max2, withinBounds) {
204
+ const result = (value - min1) / (max1 - min1) * (max2 - min2) + min2;
205
+ return withinBounds ? instance.clamp(result, min2, max2) : result;
206
+ },
207
+ /**
208
+ * Maps a number from one range to a value between 0 and 1.
209
+ * Identical to `map(value, min, max, 0, 1)`.
210
+ * Note: Numbers outside the range are not clamped to 0 and 1.
211
+ *
212
+ * @param {number} value
213
+ * @param {number} min
214
+ * @param {number} min
215
+ * @returns {number} the normalized number.
216
+ */
217
+ norm: (value, min, max) => instance.map(value, min, max, 0, 1),
218
+ /** RNG API */
219
+ /**
220
+ * Generates a pseudorandom float between min (inclusive) and max (exclusive)
221
+ * using the Linear Congruential Generator (LCG) algorithm.
222
+ *
223
+ * @param {number} [min=0.0]
224
+ * @param {number} [max=1.0]
225
+ * @returns {number} the random number
226
+ */
227
+ rand: (min = 0, max = 1) => {
228
+ const a = 1664525;
229
+ const c = 1013904223;
230
+ const m = 4294967296;
231
+ _rng_seed = (a * _rng_seed + c) % m;
232
+ return _rng_seed / m * (max - min) + min;
233
+ },
234
+ /**
235
+ * Generates a pseudorandom integer between min (inclusive) and max (inclusive)
236
+ *
237
+ * @param {number} [min=0]
238
+ * @param {number} [max=1]
239
+ * @returns {number} the random number
240
+ */
241
+ randi: (min = 0, max = 1) => Math.floor(instance.rand(min, max + 1)),
242
+ /**
243
+ * If a value is passed, initializes the random number generator with an explicit seed value.
244
+ * Otherwise, returns the current seed state.
245
+ *
246
+ * @param {number} value
247
+ * @returns {number} the seed state
248
+ */
249
+ seed: (value) => {
250
+ return null == value ? _rng_seed : _rng_seed = ~~value;
251
+ },
252
+ /** BASIC GRAPHICS API */
253
+ /**
254
+ * Clear the game screen
255
+ *
256
+ * @param {number|null} color The background color (from 0 to 7) or null (for transparent)
257
+ */
258
+ cls(color) {
259
+ if (null == color) {
260
+ _ctx.clearRect(0, 0, instance.WIDTH, instance.HEIGHT);
261
+ } else {
262
+ instance.rectfill(0, 0, instance.WIDTH, instance.HEIGHT, color);
263
+ }
264
+ },
265
+ /**
266
+ * Draw a rectangle outline
267
+ *
268
+ * @param {number} x
269
+ * @param {number} y
270
+ * @param {number} width
271
+ * @param {number} height
272
+ * @param {number} [color=0] the color index (generally from 0 to 7)
273
+ * @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
274
+ */
275
+ rect(x, y, width, height, color = 0, radii = null) {
276
+ _ctx.beginPath();
277
+ _ctx[radii ? "roundRect" : "rect"](~~x, ~~y, width, height, radii);
278
+ instance.stroke(color);
279
+ },
280
+ /**
281
+ * Draw a color-filled rectangle
282
+ *
283
+ * @param {number} x
284
+ * @param {number} y
285
+ * @param {number} width
286
+ * @param {number} height
287
+ * @param {number} [color=0] the color index (generally from 0 to 7)
288
+ * @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
289
+ */
290
+ rectfill(x, y, width, height, color = 0, radii = null) {
291
+ _ctx.beginPath();
292
+ _ctx[radii ? "roundRect" : "rect"](~~x, ~~y, width, height, radii);
293
+ instance.fill(color);
294
+ },
295
+ /**
296
+ * Draw a circle outline
297
+ *
298
+ * @param {number} x
299
+ * @param {number} y
300
+ * @param {number} radius
301
+ * @param {number} [color=0] the color index (generally from 0 to 7)
302
+ */
303
+ circ(x, y, radius, color) {
304
+ _ctx.beginPath();
305
+ _ctx.arc(~~x, ~~y, radius, 0, TWO_PI);
306
+ instance.stroke(color);
307
+ },
308
+ /**
309
+ * Draw a color-filled circle
310
+ *
311
+ * @param {number} x
312
+ * @param {number} y
313
+ * @param {number} radius
314
+ * @param {number} [color=0] the color index (generally from 0 to 7)
315
+ */
316
+ circfill(x, y, radius, color) {
317
+ _ctx.beginPath();
318
+ _ctx.arc(~~x, ~~y, radius, 0, TWO_PI);
319
+ instance.fill(color);
320
+ },
321
+ /**
322
+ * Draw a line
323
+ *
324
+ * @param {number} x1
325
+ * @param {number} y1
326
+ * @param {number} x2
327
+ * @param {number} y2
328
+ * @param {number} [color=0] the color index (generally from 0 to 7)
329
+ */
330
+ line(x1, y1, x2, y2, color) {
331
+ _ctx.beginPath();
332
+ _ctx.moveTo(~~x1, ~~y1);
333
+ _ctx.lineTo(~~x2, ~~y2);
334
+ instance.stroke(color);
335
+ },
336
+ /**
337
+ * Sets the thickness of lines
338
+ *
339
+ * @param {number} value
340
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineWidth
341
+ */
342
+ linewidth(value) {
343
+ _ctx.lineWidth = value;
344
+ },
345
+ /**
346
+ * Sets the line dash pattern used when drawing lines
347
+ *
348
+ * @param {number[]} segments the line dash pattern
349
+ * @param {number} [offset=0] the line dash offset, or "phase".
350
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
351
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
352
+ */
353
+ linedash(segments, offset = 0) {
354
+ _ctx.setLineDash(segments);
355
+ _ctx.lineDashOffset = offset;
356
+ },
357
+ /** TEXT RENDERING API */
358
+ /**
359
+ * Draw text
360
+ *
361
+ * @param {number} x
362
+ * @param {number} y
363
+ * @param {string} text the text message
364
+ * @param {number} [color=3] the color index (generally from 0 to 7)
365
+ */
366
+ text(x, y, text, color = 3) {
367
+ _ctx.font = `${_fontStyle} ${_fontSize}px ${_fontFamily}`;
368
+ _ctx.fillStyle = instance.getcolor(color);
369
+ _ctx.fillText(text, ~~x, ~~y);
370
+ },
371
+ /**
372
+ * Set the font family
373
+ *
374
+ * @param {string} fontFamily
375
+ */
376
+ textfont(fontFamily) {
377
+ _fontFamily = fontFamily;
378
+ },
379
+ /**
380
+ * Set the font size
381
+ *
382
+ * @param {string} size
383
+ */
384
+ textsize(size) {
385
+ _fontSize = size;
386
+ },
387
+ /**
388
+ * Sets whether a font should be styled with a "normal", "italic", or "bold".
389
+ *
390
+ * @param {string} style
391
+ */
392
+ textstyle(style) {
393
+ _fontStyle = style || "";
394
+ },
395
+ /**
396
+ * Sets the alignment used when drawing texts
397
+ *
398
+ * @param {string} align the horizontal alignment. Possible values: "left", "right", "center", "start" or "end"
399
+ * @param {string} baseline the vertical alignment. Possible values: "top", "bottom", "middle", "hanging" or "ideographic"
400
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textBaseline
401
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
402
+ */
403
+ textalign(align, baseline) {
404
+ if (align) _ctx.textAlign = align;
405
+ if (baseline) _ctx.textBaseline = baseline;
406
+ },
407
+ /**
408
+ * Returns a TextMetrics object that contains information about the measured text (such as its width, for example)
409
+ *
410
+ * @param {string} text
411
+ * @param {number} [size]
412
+ * @returns {TextMetrics}
413
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics
414
+ */
415
+ textmetrics(text, size = _fontSize) {
416
+ _ctx.font = `${_fontStyle} ${size}px ${_fontFamily}`;
417
+ const metrics = _ctx.measureText(text);
418
+ metrics.height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
419
+ return metrics;
420
+ },
421
+ /** IMAGE GRAPHICS API */
422
+ /**
423
+ * Draw an image
424
+ *
425
+ * @param {number} x
426
+ * @param {number} y
427
+ * @param {OffscreenCanvas|HTMLImageElement|HTMLCanvasElement} image
428
+ */
429
+ image(x, y, image) {
430
+ _ctx.drawImage(image, ~~x, ~~y);
431
+ },
432
+ /**
433
+ * Creates a offscreen canvas to draw on it
434
+ *
435
+ * @param {number} width
436
+ * @param {number} height
437
+ * @param {string[]|drawCallback} draw
438
+ * @param {object} [options]
439
+ * @param {number} [options.scale=1]
440
+ * @param {OffscreenCanvas | HTMLCanvasElement} [options.canvas]
441
+ * @returns {OffscreenCanvas}
442
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
443
+ */
444
+ paint(width, height, draw, options = {}) {
445
+ const canvas = options.canvas || new OffscreenCanvas(1, 1), scale = options.scale || 1, contextOriginal = _ctx;
446
+ canvas.width = width * scale;
447
+ canvas.height = height * scale;
448
+ _ctx = canvas.getContext("2d");
449
+ _ctx.scale(scale, scale);
450
+ if (draw.push) {
451
+ let x = 0, y = 0;
452
+ _ctx.imageSmoothingEnabled = false;
453
+ for (const str of draw) {
454
+ for (const color of str) {
455
+ if (" " !== color && "." !== color) {
456
+ instance.rectfill(x, y, 1, 1, parseInt(color, 16));
457
+ }
458
+ x++;
459
+ }
460
+ y++;
461
+ x = 0;
462
+ }
463
+ } else {
464
+ draw(_ctx);
465
+ }
466
+ _ctx = contextOriginal;
467
+ return canvas;
468
+ },
469
+ /** ADVANCED GRAPHICS API */
470
+ /**
471
+ * Get or set the canvas context 2D
472
+ *
473
+ * @param {CanvasRenderingContext2D} [context]
474
+ * @returns {CanvasRenderingContext2D}
475
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
476
+ */
477
+ ctx(context) {
478
+ if (context) {
479
+ _ctx = context;
480
+ }
481
+ return _ctx;
482
+ },
483
+ /**
484
+ * saves the current drawing style settings and transformations
485
+ *
486
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
487
+ */
488
+ push: () => _ctx.save(),
489
+ /**
490
+ * restores the drawing style settings and transformations
491
+ *
492
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore
493
+ */
494
+ pop: () => _ctx.restore(),
495
+ /**
496
+ * Adds a translation to the transformation matrix.
497
+ *
498
+ * @param {number} x
499
+ * @param {number} y
500
+ */
501
+ translate: (x, y) => _ctx.translate(~~x, ~~y),
502
+ /**
503
+ * Adds a scaling transformation to the canvas units horizontally and/or vertically.
504
+ *
505
+ * @param {number} x
506
+ * @param {number} [y]
507
+ */
508
+ scale: (x, y) => _ctx.scale(x, y || x),
509
+ /**
510
+ * Adds a rotation to the transformation matrix.
511
+ *
512
+ * @param {number} radians
513
+ */
514
+ rotate: (radians) => _ctx.rotate(radians),
515
+ /**
516
+ * @param {number} a
517
+ * @param {number} b
518
+ * @param {number} c
519
+ * @param {number} d
520
+ * @param {number} e
521
+ * @param {number} f
522
+ * @param {boolean} [resetFirst=true] `false` to use _ctx.transform(); by default use _ctx.setTransform()
523
+ *
524
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setTransform
525
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/transform
526
+ */
527
+ transform: (a, b, c, d, e, f, resetFirst = true) => _ctx[resetFirst ? "setTransform" : "transform"](a, b, c, d, e, f),
528
+ /**
529
+ * Sets the alpha (opacity) value to apply when drawing new shapes and images
530
+ *
531
+ * @param {number} alpha float from 0 to 1 (e.g: 0.5 = 50% transparent)
532
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalAlpha
533
+ */
534
+ alpha(value) {
535
+ _ctx.globalAlpha = instance.clamp(value, 0, 1);
536
+ },
537
+ /**
538
+ * Returns a newly instantiated Path2D object, optionally with another
539
+ * path as an argument (creates a copy), or optionally with a string
540
+ * consisting of SVG path data.
541
+ *
542
+ * @param {Path2D|string} [arg]
543
+ * @returns Path2D
544
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D
545
+ */
546
+ path: (arg) => new Path2D(arg),
547
+ /**
548
+ * Fills the current or given path with a given color.
549
+ *
550
+ * @param {number} [color=0]
551
+ * @param {Path2D} [path]
552
+ */
553
+ fill(color, path) {
554
+ _ctx.fillStyle = instance.getcolor(color);
555
+ if (path) {
556
+ _ctx.fill(path);
557
+ } else {
558
+ _ctx.fill();
559
+ }
560
+ },
561
+ /**
562
+ * Outlines the current or given path with a given color.
563
+ *
564
+ * @param {number} [color=0]
565
+ * @param {Path2D} [path]
566
+ */
567
+ stroke(color, path) {
568
+ _ctx.strokeStyle = instance.getcolor(color);
569
+ if (path) {
570
+ _ctx.stroke(path);
571
+ } else {
572
+ _ctx.stroke();
573
+ }
574
+ },
575
+ /**
576
+ * Turn given path into a clipping region.
577
+ *
578
+ * @param {Path2D} path
579
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip
580
+ */
581
+ clip(path) {
582
+ _ctx.clip(path);
583
+ },
584
+ /** SOUND API */
585
+ /**
586
+ * Play a sound effects using ZzFX library.
587
+ * If the first argument is omitted, plays an default sound.
588
+ *
589
+ * @param {number[]} [zzfxParams] a ZzFX array of params
590
+ * @param {number} [pitchSlide] a value to increment/decrement the pitch
591
+ * @param {number} [volumeFactor] the volume factor
592
+ * @returns {number[] | boolean} The sound that was played or `false`
593
+ *
594
+ * @see https://github.com/KilledByAPixel/ZzFX
595
+ */
596
+ sfx(zzfxParams, pitchSlide = 0, volumeFactor = 1) {
597
+ if (root.zzfxV <= 0 || navigator.userActivation && !navigator.userActivation.hasBeenActive) {
598
+ return false;
599
+ }
600
+ zzfxParams = zzfxParams || instance.DEFAULT_SFX;
601
+ if (pitchSlide > 0 || volumeFactor !== 1) {
602
+ zzfxParams = zzfxParams.slice();
603
+ zzfxParams[0] = volumeFactor * (zzfxParams[0] || 1);
604
+ zzfxParams[10] = ~~zzfxParams[10] + pitchSlide;
605
+ }
606
+ zzfx.apply(0, zzfxParams);
607
+ return zzfxParams;
608
+ },
609
+ /**
610
+ * Set the ZzFX's global volume factor.
611
+ * Note: use 0 to mute all sound effects.
612
+ *
613
+ * @param {number} value
614
+ */
615
+ volume(value) {
616
+ root.zzfxV = +value;
617
+ },
618
+ /** UTILS API */
619
+ /**
620
+ * Check a collision between two rectangles
621
+ *
622
+ * @param {number} x1 first rectangle position X
623
+ * @param {number} y1 first rectangle position Y
624
+ * @param {number} w1 first rectangle width
625
+ * @param {number} h1 first rectangle height
626
+ * @param {number} x2 second rectangle position X
627
+ * @param {number} y2 second rectangle position Y
628
+ * @param {number} w2 second rectangle width
629
+ * @param {number} h2 second rectangle height
630
+ * @returns {boolean}
631
+ */
632
+ colrect: (x1, y1, w1, h1, x2, y2, w2, h2) => x1 < x2 + w2 && x1 + w1 > x2 && y1 < y2 + h2 && y1 + h1 > y2,
633
+ /**
634
+ * Check a collision between two circles
635
+ *
636
+ * @param {number} x1 first circle position X
637
+ * @param {number} y1 first circle position Y
638
+ * @param {number} r1 first circle position radius
639
+ * @param {number} x2 second circle position X
640
+ * @param {number} y2 second circle position Y
641
+ * @param {number} r2 second circle position radius
642
+ * @returns {boolean}
643
+ */
644
+ colcirc: (x1, y1, r1, x2, y2, r2) => (x2 - x1) ** 2 + (y2 - y1) ** 2 <= (r1 + r2) ** 2,
645
+ /** PLUGINS API */
646
+ /**
647
+ * Prepares a plugin to be loaded
648
+ *
649
+ * @param {pluginCallback} callback
650
+ */
651
+ use(callback, config = {}) {
652
+ _initialized ? loadPlugin(callback, config) : _plugins.push([callback, config]);
653
+ },
654
+ /**
655
+ * Add a game event listener
656
+ *
657
+ * @param {string} eventName the event type name
658
+ * @param {Function} callback the function that is called when the event occurs
659
+ * @returns {Function} a function to remove the listener
660
+ */
661
+ listen(eventName, callback) {
662
+ _events[eventName] = _events[eventName] || /* @__PURE__ */ new Set();
663
+ _events[eventName].add(callback);
664
+ return () => _events[eventName].delete(callback);
665
+ },
666
+ /**
667
+ * Call all listeners attached to a game event
668
+ *
669
+ * @param {string} eventName The event type name
670
+ * @param {*} [arg1] any data to be passed over the listeners
671
+ * @param {*} [arg2] any data to be passed over the listeners
672
+ * @param {*} [arg3] any data to be passed over the listeners
673
+ * @param {*} [arg4] any data to be passed over the listeners
674
+ */
675
+ emit(eventName, arg1, arg2, arg3, arg4) {
676
+ triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
677
+ triggerEvent(eventName, arg1, arg2, arg3, arg4);
678
+ triggerEvent("after:" + eventName, arg1, arg2, arg3, arg4);
679
+ },
680
+ /**
681
+ * Get a color by index
682
+ *
683
+ * @param {number} [index=0] The color number
684
+ * @returns {string} the color code
685
+ */
686
+ getcolor: (index) => colors[~~index % colors.length],
687
+ /**
688
+ * Create or update a instance variable
689
+ *
690
+ * @param {string} key
691
+ * @param {*} value
692
+ */
693
+ setvar(key, value) {
694
+ instance[key] = value;
695
+ if (_global) {
696
+ root[key] = value;
697
+ }
698
+ },
699
+ /**
700
+ * Resizes the game canvas and emit the "resized" event
701
+ *
702
+ * @param {number} width
703
+ * @param {number} height
704
+ */
705
+ resize(width, height) {
706
+ instance.setvar("WIDTH", _canvas.width = width);
707
+ instance.setvar("HEIGHT", _canvas.height = height || width);
708
+ pageResized();
709
+ },
710
+ /**
711
+ * The scale of the game's delta time (dt).
712
+ * Values higher than 1 increase the speed of time, while values smaller than 1 decrease it.
713
+ * A value of 0 freezes time and is effectively equivalent to pausing.
714
+ *
715
+ * @param {number} value
716
+ */
717
+ timescale(value) {
718
+ _timeScale = value;
719
+ },
720
+ /**
721
+ * Set the target FPS at runtime.
722
+ *
723
+ * @param {number} fps
724
+ */
725
+ setfps(fps) {
726
+ _step = 1 / fps;
727
+ _stepMs = _step * 1e3;
728
+ _accumulated = 0;
729
+ },
730
+ /**
731
+ * Stops the litecanvas instance and remove all event listeners.
732
+ */
733
+ quit() {
734
+ instance.emit("quit");
735
+ for (const removeListener of _browserEventListeners) {
736
+ removeListener();
737
+ }
738
+ _focused = _events = false;
739
+ if (_global) {
740
+ for (const key in instance) {
741
+ delete root[key];
742
+ }
743
+ delete root.__litecanvas;
744
+ }
745
+ }
746
+ };
747
+ for (const k of [
748
+ "sin",
749
+ "cos",
750
+ "atan2",
751
+ "hypot",
752
+ "tan",
753
+ "abs",
754
+ "ceil",
755
+ "round",
756
+ "floor",
757
+ "trunc",
758
+ "min",
759
+ "max",
760
+ "pow",
761
+ "sqrt",
762
+ "sign",
763
+ "exp"
764
+ ]) {
765
+ instance[k] = Math[k];
766
+ }
767
+ function init() {
768
+ _initialized = true;
769
+ const source = settings.loop ? settings.loop : root;
770
+ for (const event in _events) {
771
+ if (source[event]) instance.listen(event, source[event]);
772
+ }
773
+ for (const [callback, config] of _plugins) {
774
+ loadPlugin(callback, config);
775
+ }
776
+ if (_fullscreen || _autoscale) {
777
+ on(root, "resize", pageResized);
778
+ }
779
+ pageResized();
780
+ if (settings.tapEvents) {
781
+ const _getXY = (pageX, pageY) => [
782
+ (pageX - _canvas.offsetLeft) / _scale,
783
+ (pageY - _canvas.offsetTop) / _scale
784
+ ], _taps = /* @__PURE__ */ new Map(), _registerTap = (id, x, y) => {
785
+ const tap = {
786
+ x,
787
+ y,
788
+ startX: x,
789
+ startY: y,
790
+ // timestamp
791
+ ts: performance.now()
792
+ };
793
+ _taps.set(id, tap);
794
+ return tap;
795
+ }, _updateTap = (id, x, y) => {
796
+ const tap = _taps.get(id) || _registerTap(id);
797
+ tap.x = x;
798
+ tap.y = y;
799
+ }, _checkTapped = (tap) => tap && performance.now() - tap.ts <= 200;
800
+ let _pressingMouse = false;
801
+ on(_canvas, "mousedown", (ev) => {
802
+ ev.preventDefault();
803
+ const [x, y] = _getXY(ev.pageX, ev.pageY);
804
+ instance.emit("tap", x, y, 0);
805
+ _registerTap(0, x, y);
806
+ _pressingMouse = true;
807
+ });
808
+ on(_canvas, "mousemove", (ev) => {
809
+ ev.preventDefault();
810
+ const [x, y] = _getXY(ev.pageX, ev.pageY);
811
+ instance.setvar("MOUSEX", x);
812
+ instance.setvar("MOUSEY", y);
813
+ if (!_pressingMouse) return;
814
+ instance.emit("tapping", x, y, 0);
815
+ _updateTap(0, x, y);
816
+ });
817
+ on(_canvas, "mouseup", (ev) => {
818
+ ev.preventDefault();
819
+ const tap = _taps.get(0);
820
+ const [x, y] = _getXY(ev.pageX, ev.pageY);
821
+ if (_checkTapped(tap)) {
822
+ instance.emit("tapped", tap.startX, tap.startY, 0);
823
+ }
824
+ instance.emit("untap", x, y, 0);
825
+ _taps.delete(0);
826
+ _pressingMouse = false;
827
+ });
828
+ on(_canvas, "touchstart", (ev) => {
829
+ ev.preventDefault();
830
+ const touches = ev.changedTouches;
831
+ for (const touch of touches) {
832
+ const [x, y] = _getXY(touch.pageX, touch.pageY);
833
+ instance.emit("tap", x, y, touch.identifier + 1);
834
+ _registerTap(touch.identifier + 1, x, y);
835
+ }
836
+ });
837
+ on(_canvas, "touchmove", (ev) => {
838
+ ev.preventDefault();
839
+ const touches = ev.changedTouches;
840
+ for (const touch of touches) {
841
+ const [x, y] = _getXY(touch.pageX, touch.pageY);
842
+ instance.emit("tapping", x, y, touch.identifier + 1);
843
+ _updateTap(touch.identifier + 1, x, y);
844
+ }
845
+ });
846
+ const _touchEndHandler = (ev) => {
847
+ ev.preventDefault();
848
+ const existing = [];
849
+ if (ev.targetTouches.length > 0) {
850
+ for (const touch of ev.targetTouches) {
851
+ existing.push(touch.identifier + 1);
852
+ }
853
+ }
854
+ for (const [id, tap] of _taps) {
855
+ if (existing.includes(id)) continue;
856
+ if (_checkTapped(tap)) {
857
+ instance.emit("tapped", tap.startX, tap.startY, id);
858
+ }
859
+ instance.emit("untap", tap.x, tap.y, id);
860
+ _taps.delete(id);
861
+ }
862
+ };
863
+ on(_canvas, "touchend", _touchEndHandler);
864
+ on(_canvas, "touchcancel", _touchEndHandler);
865
+ on(root, "blur", () => {
866
+ _pressingMouse = false;
867
+ for (const [id, tap] of _taps) {
868
+ instance.emit("untap", tap.x, tap.y, id);
869
+ _taps.delete(id);
870
+ }
871
+ });
872
+ }
873
+ if (settings.keyboardEvents) {
874
+ const _keys = /* @__PURE__ */ new Set();
875
+ const iskeydown = (key) => "any" === key ? _keys.size > 0 : _keys.has(key.toLowerCase());
876
+ instance.setvar("iskeydown", iskeydown);
877
+ on(root, "keydown", (event) => {
878
+ _keys.add(event.key.toLowerCase());
879
+ });
880
+ on(root, "keyup", (event) => {
881
+ _keys.delete(event.key.toLowerCase());
882
+ });
883
+ on(root, "blur", () => _keys.clear());
884
+ }
885
+ if (settings.pauseOnBlur) {
886
+ on(root, "blur", () => {
887
+ _focused = false;
888
+ });
889
+ on(root, "focus", () => {
890
+ _focused = true;
891
+ raf(drawFrame);
892
+ });
893
+ }
894
+ instance.setfps(settings.fps);
895
+ instance.emit("init", instance);
896
+ _lastFrame = performance.now();
897
+ raf(drawFrame);
898
+ }
899
+ function drawFrame(now) {
900
+ let shouldRender = !_animated, delta = now - _lastFrame;
901
+ _accumulated += delta > 100 ? _stepMs : delta;
902
+ _lastFrame = now;
903
+ while (_accumulated >= _stepMs) {
904
+ instance.emit("update", _step * _timeScale);
905
+ instance.setvar("ELAPSED", instance.ELAPSED + _step * _timeScale);
906
+ _accumulated -= _stepMs;
907
+ shouldRender = true;
908
+ }
909
+ if (shouldRender) {
910
+ instance.textalign("start", "top");
911
+ instance.emit("draw");
912
+ }
913
+ if (_focused && _animated) {
914
+ raf(drawFrame);
915
+ }
916
+ }
917
+ function setupCanvas() {
918
+ _canvas = "string" === typeof _canvas ? document.querySelector(_canvas) : _canvas;
919
+ instance.setvar("CANVAS", _canvas);
920
+ _ctx = _canvas.getContext("2d");
921
+ on(_canvas, "click", () => root.focus());
922
+ if (instance.WIDTH > 0) {
923
+ _fullscreen = false;
924
+ }
925
+ _canvas.style = "";
926
+ _canvas.width = instance.WIDTH;
927
+ _canvas.height = instance.HEIGHT || instance.WIDTH;
928
+ if (!_canvas.parentNode) document.body.appendChild(_canvas);
929
+ }
930
+ function pageResized() {
931
+ const pageWidth = root.innerWidth, pageHeight = root.innerHeight, styles = _canvas.style;
932
+ styles.display = "block";
933
+ if (_fullscreen) {
934
+ styles.position = "absolute";
935
+ styles.inset = 0;
936
+ instance.setvar("WIDTH", _canvas.width = pageWidth);
937
+ instance.setvar("HEIGHT", _canvas.height = pageHeight);
938
+ } else if (_autoscale) {
939
+ styles.margin = "auto";
940
+ _scale = Math.min(
941
+ pageWidth / instance.WIDTH,
942
+ pageHeight / instance.HEIGHT
943
+ );
944
+ _scale = (settings.pixelart ? ~~_scale : _scale) || 1;
945
+ styles.width = instance.WIDTH * _scale + "px";
946
+ styles.height = instance.HEIGHT * _scale + "px";
947
+ }
948
+ instance.setvar("CENTERX", instance.WIDTH / 2);
949
+ instance.setvar("CENTERY", instance.HEIGHT / 2);
950
+ if (!settings.antialias || settings.pixelart) {
951
+ _ctx.imageSmoothingEnabled = false;
952
+ _canvas.style.imageRendering = "pixelated";
953
+ }
954
+ instance.emit("resized", _scale);
955
+ if (!_animated) {
956
+ raf(drawFrame);
957
+ }
958
+ }
959
+ function triggerEvent(eventName, arg1, arg2, arg3, arg4) {
960
+ if (!_events[eventName]) return;
961
+ for (const callback of _events[eventName]) {
962
+ callback(arg1, arg2, arg3, arg4);
963
+ }
964
+ }
965
+ function loadPlugin(callback, config) {
966
+ const pluginData = callback(instance, _helpers, config);
967
+ if ("object" === typeof pluginData) {
968
+ for (const key of Object.keys(pluginData)) {
969
+ instance.setvar(key, pluginData[key]);
970
+ }
971
+ }
972
+ }
973
+ if (_global) {
974
+ if (root.__litecanvas) {
975
+ throw "global litecanvas already instantiated";
976
+ }
977
+ Object.assign(root, instance);
978
+ root.__litecanvas = instance;
979
+ }
980
+ setupCanvas();
981
+ if ("loading" === document.readyState) {
982
+ on(root, "DOMContentLoaded", () => raf(init));
983
+ } else {
984
+ raf(init);
985
+ }
986
+ return instance;
987
+ }
988
+
989
+ // src/noise/index.js
22
990
  var PERLIN_YWRAPB = 4;
23
991
  var PERLIN_YWRAP = 1 << PERLIN_YWRAPB;
24
992
  var PERLIN_ZWRAPB = 8;