litecanvas 0.52.0 → 0.54.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/README.md CHANGED
@@ -11,13 +11,13 @@ Litecanvas is a lightweight HTML5 canvas engine suitable for small games, animat
11
11
  ### Features
12
12
 
13
13
  - **Tiny**: Only `~4KB` (minified + gzipped).
14
- - **Simple API**: Just few functions to draw shapes and some utilities to other things like sounds and math.
14
+ - **Simple API**: Just few functions to draw shapes and some utilities.
15
15
  - **Predefined colors**: Just use a number (from 0 to 11) to choose a color in our 12-color palette.
16
- - **Predefined sounds**: Packed with 4 sounds created in [ZzFX](https://killedbyapixel.github.io/ZzFX/).
16
+ - **ZzFX**: Play or create sound effects with [ZzFX](https://killedbyapixel.github.io/ZzFX/).
17
17
  - **Extensible**: Use or create [plugins](https://www.npmjs.com/search?q=keywords:litecanvas) to add functionalities or change the engine.
18
- - **Offline Playground**: Install the [playground](https://litecanvas.js.org/) webapp and use anywhere at any time.
18
+ - **Playground**: Access or install the [playground](https://litecanvas.js.org/) webapp to code and share games (even offline).
19
19
 
20
- [Learn more...](https://litecanvas.js.org/about.html)
20
+ [Learn more in the cheatsheet...](https://litecanvas.js.org/about.html)
21
21
 
22
22
  ## Getting Started
23
23
 
@@ -38,6 +38,8 @@ npm install litecanvas
38
38
  ```
39
39
 
40
40
  ```js
41
+ // import the engine or put the script in your HTML
42
+ // CDN: https://unpkg.com/browse/litecanvas/dist/
41
43
  import litecanvas from 'litecanvas'
42
44
 
43
45
  // you can setup other configurations here
@@ -84,7 +86,7 @@ Check out our [Cheatsheet](https://litecanvas.js.org/about.html).
84
86
 
85
87
  Try some demos in our playground:
86
88
 
87
- - [Pong](https://litecanvas.js.org?c=eJy1VV1S20gQfvcpOk%2BSsMCywQlFYVIu4gWqdsMWuEL8OEgje2rlkWs0BpKQXGFPsG85RM6zF9grbPf0SJYJSe3LVhl7erqn%2B%2Fv6j0JZmQp9J6rwUwfgXmV2cQT7gyRGaSHVfGGP4OAw6XyOOp18rVOrSg1KKxtGQC9WIruBEfQHCQvnJAz5%2FJ7OiVfMUDjYJyGTlSUVWaB4K4qCxNPJ2%2Bnkqr6ZNTcz2IXzycXZ%2BRR6cODV1%2BqjrCORPNbzgi6cf2VcZD7O%2FLFaSZnheeAAVWlpavtC5bLC8z6erXyw3vfNxZvpOYY8JHMrjHXPc1FUsoNXvR4UpchAQLqubLmEvNSWvOHlL3gMg2Wpy7kRyyCGoEfaqldf7Vmb43VoZBXB6MRlEkDl%2FoZQ5Ns%2BImchMTjYhSnvITgVGnRpGQVZB2iCZfrcKpQVq5XMwocYPnC5KMQLzybyYdv0rFlLf2mkXRtNPls1%2B%2FIlfMB6uKr3YLAdbb3KhJVhZp%2BLxe4obVZZrFWVGin1a2%2FnazDCirRN52IpobyT5rVP%2BRIFTIAkBFkh%2FWvXay%2FwsYNZ8%2FIdWEizchYxq2NI9pJh5Iix06zUAeZR2pZnFIUPxUjboY4JpXdPHeTK0mi7nJ4T7qDGkPuJc9fx3rjTu5uWPvGtXnOoh6P%2FMmlk6uhXLNaty7%2B7rtGxnPlDuN8myIVxj2FVVoqq1Uxed8QTs%2BNHZAcy2wwhK2fbSnZ6W2LdvVMs%2FlaWvOc2L6b%2F%2BOijHje6miqDGMHuhkQ%2F8u23ydWz7%2BoZ33rFKNOFTP9gkGlZFKqiRr1XdrHdQagzMrUMPGbycROqfeJOooXmvm9i6EdPoNQM3I7p0g5ssCWMrT01mRH3fpmmRUUWHtOvl%2BM3F2%2FP6nmor5%2BOLy0LUai5DoNUaisN7ZulInJ%2Ba5BFheDDerttrkO%2FdeN62eLb6fh3mF7C9XR8NUVf3EmbHudeO6ERYACUuFwVRfh9augfgveA7JRJnd2Pkjx01J%2FBy6vmCVmXBuK6EHqu9LxFNuwnWBb8C%2F7%2B6%2Bs%2F3%2F6EYM%2FIlRSWwUcxHLRCeX9SZ897%2B1Hq6oGmQPgJgwA73hU92kPi14QvfIm6aDuJ%2F0fZEMZgiA7Oxr9N4PLd5Cpo0v59NndwAx4Of%2Baty9m7Pr28mhwRrf9ADpv6X2AjW9I%3D)
89
+ - [Pong](https://litecanvas.js.org?c=eJy1Vmtu20YQ%2Fs9TTH%2BRjCia1MOO3diBotJxgNQqJLW2WhQFQ66kRWmSIFexm8S5Qk6Qfz1Ez9ML9Aqd2V2%2BHNvNn1rwivPYeX4zVMIFi8L0bVha7w3Av2sei%2B0RDAeeI%2Bkt45utOILRU2Tc2oaxtwfTXSmyK%2Fj53ekllNkujUtYZwWILS9hE14x0skLJgRnRZ9v0qxgRpSlpYAXsx%2FPpwEcwy8OOOCzIX253pCOATIcGBDHgcORpwXVx0WJu6%2F093%2F99mEfi%2BVkviQXnjt2AM2MPU9dG%2BExbHsZH3jaszy0I2%2F0mPkXk9evf5udni6m8yA4Jz%2B%2BO%2FRlOmN04LkeeSU%2FeBxIb5LqH7qHeO7TSR%2FP9f3qaSDvyXMkT58yNBImIA%2FjC3TiV%2F1A%2BozocU1eEuk14hXSo6GmY1YKUiA9xXkTJknrcdU8Lvg71jJNrEm6SYhXWeOF9FZTq4Yqc8ZiJAdVKGWERWvuJnzNSiSHihTsRpBDrSvCQsjr6zApmWGsd2kkeJYCT7mwbHjfxI5K0%2BB8GcwvmyRq3gr6cBa8enm2hD0YdTyhzsWr75ZnKPAHxm3LhwjznMXWjQN%2FVJ74GqxvdFQVrxuoKHasYa9vLIk7u2YheHZFKsnbTis%2BfrRuMErZ2D0Y2J1QdnkcCmbF4v5AlFFAcAousDNlVDCWPq81dZGPseptZRpKyN6y4rkhVZF1hSROLKM44oS1wZSwIrckYFTMCtR2fTXOUlMAgbO5j2SoDaqY6pCk0WcUjzbvSRHDNjfynirHiepQrar6pWpl1BZVx3sNZk90y9uNqqDi73sdHkHloGFVqFTfffA7Le3Ouq2bWdVB9UpahTwrOTWwBdPesZqXJ3o0nkAsWohV4lVXrCYFK%2FsG12rUHgjtU%2FGVT4TLnVprx%2B3KqBJ%2B%2BKCDelbL2sVScR5Dv0m%2FCaAG%2Bm3TNJXCg8bkWnjUVJ1QtGXR7yqfKEsSXtIUXHOxbQOTXKK0YJFQOTp6d9UBtJ8UdGkTyvMCd7B9T4CtZNWq6tEe%2FYqoZQGU1FYwkW%2B17iDHRXhd760oKS3PfnSx0JYKE3zTWGbEUsEK0wHzilMJTLujVWKSVrXUuiJLL0an2oZoYzn5AZYz9VZEm0P7bi8V9E9oQptwqNRrniTWl8WkN1BtR2bHi0jqPtSaanc8kMF9NZAVohJsw3TD082dGlg%2Bvrjp3%2Fz785%2F%2F%2FPUJTLdgOQuFysZ2YHS%2FXZbGj1it9k1l3TJNnCaJDtvFvBcUlYU%2FQjz7biX%2F705iVAP8YWG%2BnHwfwOynYG52evCFOdwnnvt0%2FF9We6qKi%2BlsHhxRsl%2BVMiL9Xz8ms6Q%3D)
88
90
  - [Bouncing ball](https://litecanvas.js.org?c=eJxtUj1vgzAQ3fkVNxpCAklbqRWlQ9WqZI%2FU2TImsuQCAkOLkvz3GvsKDs3gwff8Pu7OUijOaNnTlvieJ7mCumqFElUJKfSckW0ch%2Fr4Buu5rJhQQ2Jux4b206WhuehaTbp%2F9LyiK5nREKVQxIeTBxMXdT%2F3b4cs2IXZ%2B%2F4jO0Q7P9FvUBGfxAhq6OJodnVOFSe5srp%2FeTc%2FsEonF30LIFcuPlzhg8WdYFYAI8x8h%2BHAMz2K4LXS2ThURQE8P%2FJWV0UBZE62wum8gGkbzmcn9hrBZ4htR1eRghTW2%2BRGNd48PZiyM4AUmKRfteMc4mJC64xeviZelil1fzDlxMkv8wwmz3%2FrcWWWgg7GwN1a3tBv%2FAlMtiQ2%2B2aiYYWQ0g08a4YY%2FW7xAca%2FoRsbrFrDVdeUcBor2vIXzlHggw%3D%3D)
89
91
  - [Scroller](https://litecanvas.js.org?c=eJxVUMFOwzAMvfcrzAEtacNIxwZDsAPSJoG0AxJIO0w7hDZdI6XN1HhQgfbvOOs22CGJ7ff8nh1rUGeq%2FlSe8SgqtnWGxtVgaoPAOPxEAJX2Xq01TKC30DZzlQZ0YE%2BNFz0itQQvXqbvzxRvlKVsORQjcSvuxFjci1SKNF1Fu38W202uUAPLsbNB6pnNn17fZlPKvPnWR8nrwwR9q%2Bs1loSWBI3k3vZqAjdSQgw5nsnnjfo6bpBZzySnoHANMKsRDAnIB3oe4VycaknSdQEEJoa5MGGyn8aGn8p0UDcEHdv99sNjw4yA9I%2BVOesCiX5kWVjnGoYYjy4pPdjx1Z6LusWwMQsXP5VYpVrWChhInpg4YLHsjwWUyUAm3tRBbcjjUhzGEZ1hENjRZ%2FwCV%2F6J0w%3D%3D)
90
92
  - [3D Projection](https://litecanvas.js.org?c=eJyNVU2P2jAQvfMrpodqnWI%2By6kt7WW3hVulrtTuRjk4JCyG4CDHFJYV%2F73jj5CYDUslROx579njGc844yqdMfGXFSRoteZbMVM8F8AFVySAlxZAxkW644lakGGA04IfUhjD7%2Bnt%2FQS%2BwuRu%2BmNyD9%2FKQQ9G8MmhOEbBRubL1K46hhANAOGAQh9%2FEbVTHA%2F8qbaYaaRXyLlQRaXuaB8o1D8RhV4Pwj2FZwqHyPKaaHWkAehcQ2oEf7GLwGt7pxGIqliliT6sNjDxlOlw91vHWna2m4SplCTKZsiS2sjq9gctNMxzCSRLFXAt%2FYyfLy6I3SwVT2qBpnbbigFmuSgU4jrChjVcMyX5nnS7XasKeRQYql5T5opZD5G23mbEGNCtP8Q4ElC9luVf5D6cuI5yhf%2FYzHeul1Eb3lbK6tqdaU5sPJU%2BcSVG%2BOjFOZFs56pglhWkH5gUYUSIvaLff%2F6iMAp0yDfbYkE0riQTRabTUxbBkFbFYUqoKT2j85QIdIpwCoRDGwYBvIcRrZwNfBpSECU1bmBNlwQUeAPhaIptg%2BeoR6EUMQoxdfeoag3EXREWhX39KxnaMPAM8TkjPjE%2B%2Bju6FOoNXfRNntksz%2FQlZahxF7nCZL4z2DkQO1HcIIqdKC4BRPgciN3o3XhsGQGoBX4B%2ByDcSZlLcjPFjpnxBGylpMWNuQR2VZkWZfk2Zdp46mUbBfYuhrZxnVRLq1qiyhwDh5XKVmOxXZv2YC0n5coqV3o%2Fq1zVlWB0bR1KHoWrCD5gfFZRuIwc4ei%2B1jW043ooaZXYUR9XpmorheZ42av6gWQJx2qw%2Bzr2xRdglhcngWmnojatE33El%2FVdK23y5%2BEtf86W8Xe58E6d%2B%2Bg784Ynj%2F%2FvyaU4XA%2FCq4e07onX592r6TsT7rEuw2f9d4i0%2BB%2FEGGLo)
package/dist/dist.js CHANGED
@@ -1,5 +1,6 @@
1
1
  (() => {
2
2
  // src/zzfx.js
3
+ var zzfxX = /* @__PURE__ */ new AudioContext();
3
4
  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) => {
4
5
  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;
5
6
  e = R * e + 9;
@@ -22,7 +23,6 @@
22
23
  b.connect(zzfxX.destination);
23
24
  b.start();
24
25
  };
25
- var zzfxX = /* @__PURE__ */ new AudioContext();
26
26
 
27
27
  // src/palette.js
28
28
  var colors = [
@@ -40,21 +40,9 @@
40
40
  "#a56243"
41
41
  ];
42
42
 
43
- // src/sounds.js
44
- var sounds = [
45
- // 0 - pickup
46
- [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
47
- // 1 - hit
48
- [0.7, , 820, , , , , 1.5, , 0.3, , 0.1, 1.6, , , 0.1, 0.2],
49
- // 2 - jump
50
- [0.7, , 360, 0.01, , 0.08, 1, 1.7, 12, 32, , , , , , , , 0.63, 0.02, , 99],
51
- // 3 - powerup
52
- [, , 300, 0.02, 0.1, , 1, 3.2, , , 100, 0.08, 0.1, , , , , 0.6, 0.25, 0.3]
53
- ];
54
-
55
43
  // src/index.js
56
44
  function litecanvas(settings = {}) {
57
- const root = globalThis, PI = Math.PI, TWO_PI = PI * 2, on = (elem, evt, callback) => elem.addEventListener(evt, callback), defaults = {
45
+ const root = globalThis, PI = Math.PI, TWO_PI = PI * 2, DEFAULT_SFX_SOUND = [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06], on = (elem, evt, callback) => elem.addEventListener(evt, callback), defaults = {
58
46
  fps: 60,
59
47
  fullscreen: true,
60
48
  width: null,
@@ -80,8 +68,7 @@
80
68
  tapped: false
81
69
  }, _helpers = {
82
70
  settings: Object.assign({}, settings),
83
- colors,
84
- sounds
71
+ colors
85
72
  };
86
73
  const instance = {
87
74
  /** @type {number} */
@@ -448,11 +435,18 @@
448
435
  },
449
436
  /** ADVANCED GRAPHICS API */
450
437
  /**
451
- * Get the canvas context
438
+ * Get or set the canvas context 2D
452
439
  *
440
+ * @param {CanvasRenderingContext2D} [context]
453
441
  * @returns {CanvasRenderingContext2D}
442
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
454
443
  */
455
- ctx: () => _ctx,
444
+ ctx: (context) => {
445
+ if (context) {
446
+ _ctx = context;
447
+ }
448
+ return _ctx;
449
+ },
456
450
  /**
457
451
  * saves the current drawing style settings and transformations
458
452
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
@@ -469,7 +463,7 @@
469
463
  * @param {number} x
470
464
  * @param {number} y
471
465
  */
472
- translate: (x, y) => _ctx.translate(x, y),
466
+ translate: (x, y) => _ctx.translate(~~x, ~~y),
473
467
  /**
474
468
  * Adds a scaling transformation to the canvas units horizontally and/or vertically.
475
469
  *
@@ -582,29 +576,37 @@
582
576
  },
583
577
  /** SOUND API */
584
578
  /**
585
- * Play a predefined sound or a ZzFX array of params.
586
- * By default has 4 predefined sounds.
579
+ * Play a sound made using ZzFX library.
580
+ * If the first argument is omitted, plays an default sound.
587
581
  *
588
- * @param {number|number[]} [sound=0] the sound index (from 0 to 3) or a ZzFX array of params
589
- * @param {number} [volume=1]
590
- * @param {number} [pitch=0]
591
- * @param {number} [randomness=null] an float value between 0 and 1
582
+ * @param {number|number[]} [sound] a ZzFX array of params
583
+ * @param {number} [volume] the volume factor
584
+ * @param {number} [pitch] a value to increment/decrement the pitch
585
+ * @param {number} [randomness] an float value between 0 and 1
592
586
  *
593
587
  * @see https://github.com/KilledByAPixel/ZzFX
594
- * @see https://github.com/litecanvas/game-engine/blob/main/src/sounds.js
595
588
  */
596
- sfx(sound = 0, volume = 1, pitch = 0, randomness = null) {
589
+ sfx(zzfxParams, volume, pitch, randomness) {
597
590
  if (navigator.userActivation && !navigator.userActivation.hasBeenActive) {
598
591
  return;
599
592
  }
600
- let sample = Array.isArray(sound) ? sound : sounds[sound % sounds.length];
601
- if (volume !== 1 || pitch || randomness) {
602
- sample = sample.slice();
603
- sample[0] = (Number(volume) || 1) * (sample[0] || 1);
604
- sample[1] = randomness != null ? randomness : sample[1];
605
- sample[10] = ~~sample[10] + ~~pitch;
593
+ zzfxParams = zzfxParams || DEFAULT_SFX_SOUND;
594
+ if (volume || pitch || randomness) {
595
+ zzfxParams = zzfxParams.slice();
596
+ zzfxParams[0] = (volume || 1) * (zzfxParams[0] || 1);
597
+ zzfxParams[1] = +randomness ? randomness : zzfxParams[1];
598
+ zzfxParams[10] = ~~zzfxParams[10] + ~~pitch;
606
599
  }
607
- zzfx.apply(0, sample);
600
+ zzfx.apply(0, zzfxParams);
601
+ },
602
+ /**
603
+ * Set the ZzFX's global volume.
604
+ * default: `0.3`
605
+ *
606
+ * @param {number} value
607
+ */
608
+ volume(value) {
609
+ root.zzfxV = +value || 1;
608
610
  },
609
611
  /** UTILS API */
610
612
  /**
package/dist/dist.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e=(e=1,a=.05,l=220,n=0,i=0,r=.1,o=0,s=1,c=0,f=0,p=0,u=0,g=0,d=0,h=0,m=0,v=0,b=1,T=0,x=0,H=0)=>{let y=Math,E=2*y.PI,D=c*=500*E/44100/44100,w=l*=(1-a+2*a*y.random(a=[]))*E/44100,I=0,A=0,P=0,C=1,S=0,W=0,O=0,B=H<0?-1:1,X=E*B*H*2/44100,Y=y.cos(X),k=y.sin,G=k(X)/4,_=1+G,z=-2*Y/_,L=(1-G)/_,M=(1+B*Y)/2/_,N=-(B+Y)/_,R=0,j=0,F=0,$=0;for(n=44100*n+9,T*=44100,i*=44100,r*=44100,v*=44100,f*=500*E/85766121e6,h*=E/44100,p*=E/44100,u*=44100,g=44100*g|0,e*=globalThis.zzfxV||.3,B=n+T+i+r+v|0;P<B;a[P++]=O*e)++W%(100*m|0)||(O=o?1<o?2<o?3<o?k(I*I):y.max(y.min(y.tan(I),1),-1):1-(2*I/E%2+2)%2:1-4*y.abs(y.round(I/E)-I/E):k(I),O=(g?1-x+x*k(E*P/g):1)*(O<0?-1:1)*y.abs(O)**s*(P<n?P/n:P<n+T?1-(P-n)/T*(1-b):P<n+T+i?b:P<B-v?(B-P-v)/r*b:0),O=v?O/2+(v>P?0:(P<B-v?1:(B-P)/v)*a[P-v|0]/2/e):O,H&&(O=$=M*R+N*(R=j)+M*(j=O)-L*F-z*(F=$))),I+=(X=(l+=c+=f)*y.cos(h*A++))+X*d*k(P**5),C&&++C>u&&(l+=p,w+=p,C=0),!g||++S%g||(l=w,c=D,C=C||1);(e=t.createBuffer(1,B,44100)).getChannelData(0).set(a),(l=t.createBufferSource()).buffer=e,l.connect(t.destination),l.start()},t=/* @__PURE__ */new AudioContext,a=["#18161c","#6a7799","#aec2c2","#f3eade","#f04f78","#fcf660","#2f328f","#4b80ca","#327345","#63c64d","#703075","#a56243"],l=[[.5,,1675,,.06,.2,1,1.8,,,637,.06],[.7,,820,,,,,1.5,,.3,,.1,1.6,,,.1,.2],[.7,,360,.01,,.08,1,1.7,12,32,,,,,,,,.63,.02,,99],[,,300,.02,.1,,1,3.2,,,100,.08,.1,,,,,.6,.25,.3]];globalThis.litecanvas=function(t={}){let n=globalThis,i=Math.PI,r=2*i,o=(e,t,a)=>e.addEventListener(t,a);t=Object.assign({fps:60,fullscreen:!0,width:null,height:null,autoscale:!0,pixelart:!1,antialias:!0,canvas:null,global:!0,loop:null,tapEvents:!0,pauseOnBlur:!0},t);let s=!1,c=[],f=t.canvas||document.createElement("canvas"),p=t.fullscreen,u=t.autoscale,g=1,d,h,m,v=1,b,T=1/t.fps,x=1e3*T,H=0,y,E=0,D=0,w="sans-serif",I="",A=32,P=Date.now(),C={init:!1,update:!1,draw:!1,resized:!1,tap:!1,untap:!1,tapping:!1,tapped:!1},S={settings:Object.assign({},t),colors:a,sounds:l},W={WIDTH:t.width,HEIGHT:t.height||t.width,CANVAS:null,ELAPSED:0,FPS:t.fps,CENTERX:null,CENTERY:null,PI:i,TWO_PI:r,HALF_PI:.5*i,lerp:(e,t,a)=>e+a*(t-e),deg2rad:e=>i/180*e,rad2deg:e=>180/i*e,clamp:(e,t,a)=>e<t?t:e>a?a:e,wrap:(e,t,a)=>e-(a-t)*Math.floor((e-t)/(a-t)),map(e,t,a,l,n,i=!1){let r=(e-t)/(a-t)*(n-l)+l;return i?W.clamp(r,l,n):r},norm:(e,t,a)=>W.map(e,t,a,0,1),rand:(e=0,t=1)=>(P=(1664525*P+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>W.floor(W.rand()*(t-e+1)+e),seed:e=>null==e?P:P=~~e,cls(e){null==e?m.clearRect(0,0,W.WIDTH,W.HEIGHT):W.rectfill(0,0,W.WIDTH,W.HEIGHT,e)},rect(e,t,a,l,n=0,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e,~~t,a,l,i),W.stroke(n)},rectfill(e,t,a,l,n=0,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e,~~t,a,l,i),W.fill(n)},circ(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,a,0,r),m.closePath(),W.stroke(l)},circfill(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,a,0,r),m.closePath(),W.fill(l)},line(e,t,a,l,n){m.beginPath(),m.moveTo(~~e,~~t),m.lineTo(~~a,~~l),W.stroke(n)},linewidth(e){m.lineWidth=e},linedash(e,t=0){m.setLineDash(Array.isArray(e)?e:[e]),m.lineDashOffset=t},text(e,t,a,l=3){m.font=`${I||""} ${A}px ${w}`,m.fillStyle=W.getcolor(l),m.fillText(a,~~e,~~t)},textfont(e){w=e},textsize(e){A=e},textstyle(e){I=e},textalign(e,t){e&&(m.textAlign=e),t&&(m.textBaseline=t)},textmetrics(e,t){m.font=`${I||""} ${t||A}px ${w}`;let a=m.measureText(e);return a.height=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent,a},image(e,t,a){m.drawImage(a,~~e,~~t)},paint(e,t,a,l={}){let n=new OffscreenCanvas(e,t),i=m,r=l.scale||1;if(n.width=e*r,n.height=t*r,(m=n.getContext("2d")).scale(r,r),Array.isArray(a)){let e=0,t=0;for(let l of(m.imageSmoothingEnabled=!1,a)){for(let a of l)" "!==a&&"."!==a&&W.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(n,m);return m=i,n},ctx:()=>m,push:()=>m.save(),pop:()=>m.restore(),translate:(e,t)=>m.translate(e,t),scale:(e,t)=>m.scale(e,t||e),rotate:e=>m.rotate(e),transform:(e,t,a,l,n,i,r=!0)=>m[r?"setTransform":"transform"](e,t,a,l,n,i),alpha(e){m.globalAlpha=W.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){m.fillStyle=W.getcolor(e),m.fill(t)},stroke(e,t){m.strokeStyle=W.getcolor(e),t?m.stroke(t):m.stroke()},cliprect(e,t,a,l){m.beginPath(),m.rect(e,t,a,l),m.clip()},clipcirc(e,t,a){m.beginPath(),m.arc(e,t,a,0,r),m.clip()},blendmode(e){m.globalCompositeOperation=e},sfx(t=0,a=1,n=0,i=null){if(navigator.userActivation&&!navigator.userActivation.hasBeenActive)return;let r=Array.isArray(t)?t:l[t%l.length];(1!==a||n||i)&&((r=r.slice())[0]=(Number(a)||1)*(r[0]||1),r[1]=null!=i?i:r[1],r[10]=~~r[10]+~~n),e.apply(0,r)},colrect:(e,t,a,l,n,i,r,o)=>e<n+r&&e+a>n&&t<i+o&&t+l>i,colcirc:(e,t,a,l,n,i)=>(l-e)**2+(n-t)**2<=(a+i)**2,mousepos:()=>[d,h],timescale(e){v=e},use(e,t={}){e.__conf=t,s?k(e):c.push(e)},listen:(e,t)=>(C[e]=C[e]||[],C[e].push(t),()=>{C[e]=C[e].filter(e=>t!==e)}),emit(e,t,a,l,n){Y("before:"+e,t,a,l,n),Y(e,t,a,l,n),Y("after:"+e,t,a,l,n)},getcolor:e=>a[~~e%a.length],setvar(e,a){W[e]=a,t.global&&(n[e]=a)},resize(e,t){W.setvar("WIDTH",f.width=e),W.setvar("HEIGHT",f.height=t||e),X()}};for(let e of["sin","cos","atan2","hypot","tan","abs","ceil","round","floor","trunc","min","max","pow","sqrt","sign","exp"])W[e]=Math[e];function O(){s=!0,f="string"==typeof f?document.querySelector(f):f,W.setvar("CANVAS",f),m=f.getContext("2d"),W.WIDTH>0&&(p=!1),f.width=W.WIDTH,f.height=W.HEIGHT||W.WIDTH,f.parentNode||document.body.appendChild(f),f.style.display="block",p?(f.style.position="absolute",f.style.inset=0):u&&(f.style.margin="auto");let e=t.loop?t.loop:n;for(let t of Object.keys(C))e[t]&&W.listen(t,e[t]);for(let e of c)k(e);if(o(n,"resize",X),X(),t.tapEvents){let e=(e,t)=>[(e-f.offsetLeft)/g,(t-f.offsetTop)/g],t=/* @__PURE__ */new Map,a=(e,a,l)=>{let n={x:a,y:l,startX:a,startY:l,ts:performance.now()};return t.set(e,n),n},l=(e,l,n)=>{let i=t.get(e)||a(e);i.x=l,i.y=n},i=e=>e&&performance.now()-e.ts<=200,r=!1;o(f,"mousedown",t=>{t.preventDefault();let[l,n]=e(t.pageX,t.pageY);W.emit("tap",l,n,0),a(0,l,n),r=!0}),o(f,"mousemove",t=>{t.preventDefault();let[a,n]=[d,h]=e(t.pageX,t.pageY);r&&(W.emit("tapping",a,n,0),l(0,a,n))}),o(f,"mouseup",a=>{a.preventDefault();let l=t.get(0),[n,o]=e(a.pageX,a.pageY);i(l)&&W.emit("tapped",l.startX,l.startY,0),W.emit("untap",n,o,0),t.delete(0),r=!1}),o(f,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l.pageX,l.pageY);W.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),o(f,"touchmove",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,n]=e(a.pageX,a.pageY);W.emit("tapping",t,n,a.identifier+1),l(a.identifier+1,t,n)}});let s=e=>{e.preventDefault();let a=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,l]of t)a.includes(e)||(i(l)&&W.emit("tapped",l.startX,l.startY,e),W.emit("untap",l.x,l.y,e),t.delete(e))};o(f,"touchend",s),o(f,"touchcancel",s),o(n,"blur",()=>{if(r=!1,0!==t.size)for(let[e,a]of t)W.emit("untap",a.x,a.y,e),t.delete(e)})}t.pauseOnBlur&&(o(n,"blur",()=>{y=null}),o(n,"focus",()=>{y||(b=performance.now(),y=requestAnimationFrame(B))})),W.emit("init"),b=performance.now(),y=requestAnimationFrame(B)}function B(e){let t=0,a=e-b;for(b=e,H+=a;H>=x;)W.emit("update",T*v),W.setvar("ELAPSED",W.ELAPSED+T*v),H-=x,t++;t&&(W.textalign("start","top"),W.emit("draw"),E++,(D+=x*t)+H>=1e3&&(W.setvar("FPS",E),E=0,D-=1e3)),y&&(y=requestAnimationFrame(B))}function X(){let e=n.innerWidth,a=n.innerHeight;p?(W.setvar("WIDTH",f.width=e),W.setvar("HEIGHT",f.height=a)):u&&(g=Math.min(e/W.WIDTH,a/W.HEIGHT),g=t.pixelart?Math.floor(g):g,f.style.width=W.WIDTH*g+"px",f.style.height=W.HEIGHT*g+"px"),W.setvar("CENTERX",W.WIDTH/2),W.setvar("CENTERY",W.HEIGHT/2),(!t.antialias||t.pixelart)&&(m.imageSmoothingEnabled=!1,f.style.imageRendering="pixelated"),W.emit("resized",g)}function Y(e,t,a,l,n){if(C[e])for(let i of C[e])i(t,a,l,n)}function k(e){let t=e(W,S,e.__conf);if("object"==typeof t)for(let[e,a]of Object.entries(t))W.setvar(e,a)}if(t.global){if(n.__litecanvas)throw"Cannot instantiate litecanvas globally twice";Object.assign(n,W),n.__litecanvas=W}return"loading"===document.readyState?o(n,"DOMContentLoaded",O):O(),W}})();
1
+ (()=>{var e=/* @__PURE__ */new AudioContext,t=(t=1,a=.05,l=220,n=0,i=0,r=.1,o=0,s=1,c=0,f=0,p=0,u=0,g=0,d=0,h=0,m=0,v=0,x=1,T=0,b=0,H=0)=>{let E=Math,y=2*E.PI,D=c*=500*y/44100/44100,w=l*=(1-a+2*a*E.random(a=[]))*y/44100,I=0,A=0,P=0,C=1,S=0,W=0,O=0,z=H<0?-1:1,B=y*z*H*2/44100,X=E.cos(B),Y=E.sin,k=Y(B)/4,G=1+k,_=-2*X/G,L=(1-k)/G,M=(1+z*X)/2/G,R=-(z+X)/G,N=0,j=0,F=0,$=0;for(n=44100*n+9,T*=44100,i*=44100,r*=44100,v*=44100,f*=500*y/85766121e6,h*=y/44100,p*=y/44100,u*=44100,g=44100*g|0,t*=globalThis.zzfxV||.3,z=n+T+i+r+v|0;P<z;a[P++]=O*t)++W%(100*m|0)||(O=o?1<o?2<o?3<o?Y(I*I):E.max(E.min(E.tan(I),1),-1):1-(2*I/y%2+2)%2:1-4*E.abs(E.round(I/y)-I/y):Y(I),O=(g?1-b+b*Y(y*P/g):1)*(O<0?-1:1)*E.abs(O)**s*(P<n?P/n:P<n+T?1-(P-n)/T*(1-x):P<n+T+i?x:P<z-v?(z-P-v)/r*x:0),O=v?O/2+(v>P?0:(P<z-v?1:(z-P)/v)*a[P-v|0]/2/t):O,H&&(O=$=M*N+R*(N=j)+M*(j=O)-L*F-_*(F=$))),I+=(B=(l+=c+=f)*E.cos(h*A++))+B*d*Y(P**5),C&&++C>u&&(l+=p,w+=p,C=0),!g||++S%g||(l=w,c=D,C=C||1);(t=e.createBuffer(1,z,44100)).getChannelData(0).set(a),(l=e.createBufferSource()).buffer=t,l.connect(e.destination),l.start()},a=["#18161c","#6a7799","#aec2c2","#f3eade","#f04f78","#fcf660","#2f328f","#4b80ca","#327345","#63c64d","#703075","#a56243"];globalThis.litecanvas=function(e={}){let l=globalThis,n=Math.PI,i=2*n,r=[.5,,1675,,.06,.2,1,1.8,,,637,.06],o=(e,t,a)=>e.addEventListener(t,a);e=Object.assign({fps:60,fullscreen:!0,width:null,height:null,autoscale:!0,pixelart:!1,antialias:!0,canvas:null,global:!0,loop:null,tapEvents:!0,pauseOnBlur:!0},e);let s=!1,c=[],f=e.canvas||document.createElement("canvas"),p=e.fullscreen,u=e.autoscale,g=1,d,h,m,v=1,x,T=1/e.fps,b=1e3*T,H=0,E,y=0,D=0,w="sans-serif",I="",A=32,P=Date.now(),C={init:!1,update:!1,draw:!1,resized:!1,tap:!1,untap:!1,tapping:!1,tapped:!1},S={settings:Object.assign({},e),colors:a},W={WIDTH:e.width,HEIGHT:e.height||e.width,CANVAS:null,ELAPSED:0,FPS:e.fps,CENTERX:null,CENTERY:null,PI:n,TWO_PI:i,HALF_PI:.5*n,lerp:(e,t,a)=>e+a*(t-e),deg2rad:e=>n/180*e,rad2deg:e=>180/n*e,clamp:(e,t,a)=>e<t?t:e>a?a:e,wrap:(e,t,a)=>e-(a-t)*Math.floor((e-t)/(a-t)),map(e,t,a,l,n,i=!1){let r=(e-t)/(a-t)*(n-l)+l;return i?W.clamp(r,l,n):r},norm:(e,t,a)=>W.map(e,t,a,0,1),rand:(e=0,t=1)=>(P=(1664525*P+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>W.floor(W.rand()*(t-e+1)+e),seed:e=>null==e?P:P=~~e,cls(e){null==e?m.clearRect(0,0,W.WIDTH,W.HEIGHT):W.rectfill(0,0,W.WIDTH,W.HEIGHT,e)},rect(e,t,a,l,n=0,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e,~~t,a,l,i),W.stroke(n)},rectfill(e,t,a,l,n=0,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e,~~t,a,l,i),W.fill(n)},circ(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,a,0,i),m.closePath(),W.stroke(l)},circfill(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,a,0,i),m.closePath(),W.fill(l)},line(e,t,a,l,n){m.beginPath(),m.moveTo(~~e,~~t),m.lineTo(~~a,~~l),W.stroke(n)},linewidth(e){m.lineWidth=e},linedash(e,t=0){m.setLineDash(Array.isArray(e)?e:[e]),m.lineDashOffset=t},text(e,t,a,l=3){m.font=`${I||""} ${A}px ${w}`,m.fillStyle=W.getcolor(l),m.fillText(a,~~e,~~t)},textfont(e){w=e},textsize(e){A=e},textstyle(e){I=e},textalign(e,t){e&&(m.textAlign=e),t&&(m.textBaseline=t)},textmetrics(e,t){m.font=`${I||""} ${t||A}px ${w}`;let a=m.measureText(e);return a.height=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent,a},image(e,t,a){m.drawImage(a,~~e,~~t)},paint(e,t,a,l={}){let n=new OffscreenCanvas(e,t),i=m,r=l.scale||1;if(n.width=e*r,n.height=t*r,(m=n.getContext("2d")).scale(r,r),Array.isArray(a)){let e=0,t=0;for(let l of(m.imageSmoothingEnabled=!1,a)){for(let a of l)" "!==a&&"."!==a&&W.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(n,m);return m=i,n},ctx:e=>(e&&(m=e),m),push:()=>m.save(),pop:()=>m.restore(),translate:(e,t)=>m.translate(~~e,~~t),scale:(e,t)=>m.scale(e,t||e),rotate:e=>m.rotate(e),transform:(e,t,a,l,n,i,r=!0)=>m[r?"setTransform":"transform"](e,t,a,l,n,i),alpha(e){m.globalAlpha=W.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){m.fillStyle=W.getcolor(e),m.fill(t)},stroke(e,t){m.strokeStyle=W.getcolor(e),t?m.stroke(t):m.stroke()},cliprect(e,t,a,l){m.beginPath(),m.rect(e,t,a,l),m.clip()},clipcirc(e,t,a){m.beginPath(),m.arc(e,t,a,0,i),m.clip()},blendmode(e){m.globalCompositeOperation=e},sfx(e,a,l,n){(!navigator.userActivation||navigator.userActivation.hasBeenActive)&&(e=e||r,(a||l||n)&&((e=e.slice())[0]=(a||1)*(e[0]||1),e[1]=+n?n:e[1],e[10]=~~e[10]+~~l),t.apply(0,e))},volume(e){l.zzfxV=+e||1},colrect:(e,t,a,l,n,i,r,o)=>e<n+r&&e+a>n&&t<i+o&&t+l>i,colcirc:(e,t,a,l,n,i)=>(l-e)**2+(n-t)**2<=(a+i)**2,mousepos:()=>[d,h],timescale(e){v=e},use(e,t={}){e.__conf=t,s?Y(e):c.push(e)},listen:(e,t)=>(C[e]=C[e]||[],C[e].push(t),()=>{C[e]=C[e].filter(e=>t!==e)}),emit(e,t,a,l,n){X("before:"+e,t,a,l,n),X(e,t,a,l,n),X("after:"+e,t,a,l,n)},getcolor:e=>a[~~e%a.length],setvar(t,a){W[t]=a,e.global&&(l[t]=a)},resize(e,t){W.setvar("WIDTH",f.width=e),W.setvar("HEIGHT",f.height=t||e),B()}};for(let e of["sin","cos","atan2","hypot","tan","abs","ceil","round","floor","trunc","min","max","pow","sqrt","sign","exp"])W[e]=Math[e];function O(){s=!0,f="string"==typeof f?document.querySelector(f):f,W.setvar("CANVAS",f),m=f.getContext("2d"),W.WIDTH>0&&(p=!1),f.width=W.WIDTH,f.height=W.HEIGHT||W.WIDTH,f.parentNode||document.body.appendChild(f),f.style.display="block",p?(f.style.position="absolute",f.style.inset=0):u&&(f.style.margin="auto");let t=e.loop?e.loop:l;for(let e of Object.keys(C))t[e]&&W.listen(e,t[e]);for(let e of c)Y(e);if(o(l,"resize",B),B(),e.tapEvents){let e=(e,t)=>[(e-f.offsetLeft)/g,(t-f.offsetTop)/g],t=/* @__PURE__ */new Map,a=(e,a,l)=>{let n={x:a,y:l,startX:a,startY:l,ts:performance.now()};return t.set(e,n),n},n=(e,l,n)=>{let i=t.get(e)||a(e);i.x=l,i.y=n},i=e=>e&&performance.now()-e.ts<=200,r=!1;o(f,"mousedown",t=>{t.preventDefault();let[l,n]=e(t.pageX,t.pageY);W.emit("tap",l,n,0),a(0,l,n),r=!0}),o(f,"mousemove",t=>{t.preventDefault();let[a,l]=[d,h]=e(t.pageX,t.pageY);r&&(W.emit("tapping",a,l,0),n(0,a,l))}),o(f,"mouseup",a=>{a.preventDefault();let l=t.get(0),[n,o]=e(a.pageX,a.pageY);i(l)&&W.emit("tapped",l.startX,l.startY,0),W.emit("untap",n,o,0),t.delete(0),r=!1}),o(f,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l.pageX,l.pageY);W.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),o(f,"touchmove",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,l]=e(a.pageX,a.pageY);W.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let s=e=>{e.preventDefault();let a=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,l]of t)a.includes(e)||(i(l)&&W.emit("tapped",l.startX,l.startY,e),W.emit("untap",l.x,l.y,e),t.delete(e))};o(f,"touchend",s),o(f,"touchcancel",s),o(l,"blur",()=>{if(r=!1,0!==t.size)for(let[e,a]of t)W.emit("untap",a.x,a.y,e),t.delete(e)})}e.pauseOnBlur&&(o(l,"blur",()=>{E=null}),o(l,"focus",()=>{E||(x=performance.now(),E=requestAnimationFrame(z))})),W.emit("init"),x=performance.now(),E=requestAnimationFrame(z)}function z(e){let t=0,a=e-x;for(x=e,H+=a;H>=b;)W.emit("update",T*v),W.setvar("ELAPSED",W.ELAPSED+T*v),H-=b,t++;t&&(W.textalign("start","top"),W.emit("draw"),y++,(D+=b*t)+H>=1e3&&(W.setvar("FPS",y),y=0,D-=1e3)),E&&(E=requestAnimationFrame(z))}function B(){let t=l.innerWidth,a=l.innerHeight;p?(W.setvar("WIDTH",f.width=t),W.setvar("HEIGHT",f.height=a)):u&&(g=Math.min(t/W.WIDTH,a/W.HEIGHT),g=e.pixelart?Math.floor(g):g,f.style.width=W.WIDTH*g+"px",f.style.height=W.HEIGHT*g+"px"),W.setvar("CENTERX",W.WIDTH/2),W.setvar("CENTERY",W.HEIGHT/2),(!e.antialias||e.pixelart)&&(m.imageSmoothingEnabled=!1,f.style.imageRendering="pixelated"),W.emit("resized",g)}function X(e,t,a,l,n){if(C[e])for(let i of C[e])i(t,a,l,n)}function Y(e){let t=e(W,S,e.__conf);if("object"==typeof t)for(let[e,a]of Object.entries(t))W.setvar(e,a)}if(e.global){if(l.__litecanvas)throw"Cannot instantiate litecanvas globally twice";Object.assign(l,W),l.__litecanvas=W}return"loading"===document.readyState?o(l,"DOMContentLoaded",O):O(),W}})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.52.0",
3
+ "version": "0.54.0",
4
4
  "description": "Lightweight HTML5 canvas engine suitable for small games and animations.",
5
5
  "license": "MIT",
6
6
  "author": "Luiz Bills <luizbills@pm.me>",
package/src/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { zzfx } from './zzfx.js'
2
2
  import { colors } from './palette.js'
3
- import { sounds } from './sounds.js'
4
3
  import './types.js'
5
4
 
6
5
  /**
@@ -13,6 +12,7 @@ export default function litecanvas(settings = {}) {
13
12
  const root = globalThis,
14
13
  PI = Math.PI,
15
14
  TWO_PI = PI * 2,
15
+ DEFAULT_SFX_SOUND = [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
16
16
  /** @type {(elem:HTMLElement, evt:string, callback:(event:Event)=>void)=>void} */
17
17
  on = (elem, evt, callback) => elem.addEventListener(evt, callback),
18
18
  /** @type {LitecanvasOptions} */
@@ -97,7 +97,6 @@ export default function litecanvas(settings = {}) {
97
97
  _helpers = {
98
98
  settings: Object.assign({}, settings),
99
99
  colors,
100
- sounds,
101
100
  }
102
101
 
103
102
  /** @type {LitecanvasInstance} */
@@ -516,11 +515,18 @@ export default function litecanvas(settings = {}) {
516
515
 
517
516
  /** ADVANCED GRAPHICS API */
518
517
  /**
519
- * Get the canvas context
518
+ * Get or set the canvas context 2D
520
519
  *
520
+ * @param {CanvasRenderingContext2D} [context]
521
521
  * @returns {CanvasRenderingContext2D}
522
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
522
523
  */
523
- ctx: () => _ctx,
524
+ ctx: (context) => {
525
+ if (context) {
526
+ _ctx = context
527
+ }
528
+ return _ctx
529
+ },
524
530
 
525
531
  /**
526
532
  * saves the current drawing style settings and transformations
@@ -540,7 +546,7 @@ export default function litecanvas(settings = {}) {
540
546
  * @param {number} x
541
547
  * @param {number} y
542
548
  */
543
- translate: (x, y) => _ctx.translate(x, y),
549
+ translate: (x, y) => _ctx.translate(~~x, ~~y),
544
550
 
545
551
  /**
546
552
  * Adds a scaling transformation to the canvas units horizontally and/or vertically.
@@ -665,18 +671,17 @@ export default function litecanvas(settings = {}) {
665
671
 
666
672
  /** SOUND API */
667
673
  /**
668
- * Play a predefined sound or a ZzFX array of params.
669
- * By default has 4 predefined sounds.
674
+ * Play a sound made using ZzFX library.
675
+ * If the first argument is omitted, plays an default sound.
670
676
  *
671
- * @param {number|number[]} [sound=0] the sound index (from 0 to 3) or a ZzFX array of params
672
- * @param {number} [volume=1]
673
- * @param {number} [pitch=0]
674
- * @param {number} [randomness=null] an float value between 0 and 1
677
+ * @param {number|number[]} [sound] a ZzFX array of params
678
+ * @param {number} [volume] the volume factor
679
+ * @param {number} [pitch] a value to increment/decrement the pitch
680
+ * @param {number} [randomness] an float value between 0 and 1
675
681
  *
676
682
  * @see https://github.com/KilledByAPixel/ZzFX
677
- * @see https://github.com/litecanvas/game-engine/blob/main/src/sounds.js
678
683
  */
679
- sfx(sound = 0, volume = 1, pitch = 0, randomness = null) {
684
+ sfx(zzfxParams, volume, pitch, randomness) {
680
685
  if (
681
686
  navigator.userActivation &&
682
687
  !navigator.userActivation.hasBeenActive
@@ -684,17 +689,28 @@ export default function litecanvas(settings = {}) {
684
689
  return
685
690
  }
686
691
 
687
- let sample = Array.isArray(sound)
688
- ? sound
689
- : sounds[sound % sounds.length]
690
- if (volume !== 1 || pitch || randomness) {
691
- sample = sample.slice()
692
- sample[0] = (Number(volume) || 1) * (sample[0] || 1)
693
- sample[1] = randomness != null ? randomness : sample[1]
694
- sample[10] = ~~sample[10] + ~~pitch
692
+ // prettier-ignore
693
+ zzfxParams = zzfxParams || DEFAULT_SFX_SOUND
694
+
695
+ // if has other arguments, copy the sound to not change the original
696
+ if (volume || pitch || randomness) {
697
+ zzfxParams = zzfxParams.slice()
698
+ zzfxParams[0] = (volume || 1) * (zzfxParams[0] || 1)
699
+ zzfxParams[1] = +randomness ? randomness : zzfxParams[1]
700
+ zzfxParams[10] = ~~zzfxParams[10] + ~~pitch
695
701
  }
696
702
 
697
- zzfx.apply(0, sample)
703
+ zzfx.apply(0, zzfxParams)
704
+ },
705
+
706
+ /**
707
+ * Set the ZzFX's global volume.
708
+ * default: `0.3`
709
+ *
710
+ * @param {number} value
711
+ */
712
+ volume(value) {
713
+ root.zzfxV = +value || 1
698
714
  },
699
715
 
700
716
  /** UTILS API */
package/src/types.js CHANGED
@@ -43,14 +43,13 @@
43
43
  /**
44
44
  * @typedef LitecanvasPluginHelpers
45
45
  * @type {object}
46
- * @property {string[]} colors - the instance color palette
47
- * @property {number[][]} sounds - the instance ZzFX sounds
48
- * @property {LitecanvasOptions} settings - an copy of this instance settings
46
+ * @property {string[]} colors The instance color palette
47
+ * @property {LitecanvasOptions} settings An copy of this instance settings
49
48
  */
50
49
 
51
50
  /**
52
51
  * @callback pluginCallback
53
- * @param {LitecanvasInstance} instance - The litecanvas instance
52
+ * @param {LitecanvasInstance} instance The litecanvas instance
54
53
  * @param {LitecanvasPluginHelpers} helpers
55
54
  * @returns
56
55
  */
package/src/zzfx.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // ZzFXMicro - Zuper Zmall Zound Zynth - v1.3.0 by Frank Force | https://github.com/KilledByAPixel/ZzFX
2
+ const zzfxX = /** @__PURE__ */ new AudioContext()
2
3
  export const zzfx = (
3
4
  p = 1,
4
5
  k = 0.05,
@@ -107,5 +108,3 @@ export const zzfx = (
107
108
  b.connect(zzfxX.destination)
108
109
  b.start()
109
110
  }
110
-
111
- const zzfxX = /** @__PURE__ */ new AudioContext()
package/types/index.d.ts CHANGED
@@ -346,6 +346,7 @@ declare global {
346
346
  * @see https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics
347
347
  */
348
348
  function textmetrics(text: string, size?: number): TextMetrics
349
+
349
350
  /** IMAGE GRAPHICS API */
350
351
  /**
351
352
  * Draw an image
@@ -377,13 +378,13 @@ declare global {
377
378
  scale?: number
378
379
  }
379
380
  ): OffscreenCanvas
381
+
380
382
  /** ADVANCED GRAPHICS API */
381
383
  /**
382
- * Get the canvas context
383
- *
384
- * @returns {CanvasRenderingContext2D}
384
+ * Get or set the canvas context 2D
385
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
385
386
  */
386
- function ctx(): CanvasRenderingContext2D
387
+ function ctx(value?: CanvasRenderingContext2D): CanvasRenderingContext2D
387
388
  /**
388
389
  * saves the current drawing style settings and transformations
389
390
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
@@ -501,25 +502,33 @@ declare global {
501
502
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
502
503
  */
503
504
  function blendmode(value: string): void
505
+
504
506
  /** SOUND API */
505
507
  /**
506
- * Play a predefined sound or a ZzFX array of params.
507
- * By default has 4 predefined sounds.
508
+ * Play a sound made using ZzFX library.
509
+ * If the first argument is omitted, plays an default sound.
510
+ *
511
+ * @param {number|number[]} [sound] a ZzFX array of params
512
+ * @param {number} [volume] the volume factor
513
+ * @param {number} [pitch] a value to increment/decrement the pitch
514
+ * @param {number} [randomness] an float between 0 and 1
508
515
  *
509
- * @param {number|number[]} [sound=0] the sound index (from 0 to 3) or a ZzFX array of params
510
- * @param {number} [volume=1] the volume factor
511
- * @param {number} [pitch=0] a value to increment/decrement the pitch
512
- * @param {number} [randomness=null] an float between 0 and 1
513
- * @returns {AudioBufferSourceNode}
514
516
  * @see https://github.com/KilledByAPixel/ZzFX
515
- * @see https://github.com/litecanvas/game-engine/blob/main/src/sounds.js
516
517
  */
517
518
  function sfx(
518
- sound?: number | number[],
519
+ sound?: number[],
519
520
  volume?: number,
520
521
  pitch?: number,
521
522
  randomness?: number
522
- ): AudioBufferSourceNode
523
+ ): void
524
+ /**
525
+ * Set the ZzFX's global volume.
526
+ * default: `0.3`
527
+ *
528
+ * @param {number} value
529
+ */
530
+ function volume(value: number): void
531
+
523
532
  /** UTILS API */
524
533
  /**
525
534
  * Check a collision between two rectangles
@@ -593,10 +602,7 @@ declare global {
593
602
  * @param {boolean} [highPriority=false] determines whether the callback will be called before or after the others
594
603
  * @returns {function?} a function to remove the listener
595
604
  */
596
- function listen(
597
- event: string,
598
- callback: Function
599
- ): Function | null
605
+ function listen(event: string, callback: Function): Function | null
600
606
  /**
601
607
  * Call all listeners attached to a game event
602
608
  *
package/types/types.d.ts CHANGED
@@ -364,11 +364,10 @@ type LitecanvasInstance = {
364
364
 
365
365
  /** ADVANCED GRAPHICS API */
366
366
  /**
367
- * Get the canvas context
368
- *
369
- * @returns {CanvasRenderingContext2D}
367
+ * Get or set the canvas context 2D
368
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
370
369
  */
371
- ctx(): CanvasRenderingContext2D
370
+ ctx(value?: CanvasRenderingContext2D): CanvasRenderingContext2D
372
371
  /**
373
372
  * saves the current drawing style settings and transformations
374
373
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
@@ -489,23 +488,29 @@ type LitecanvasInstance = {
489
488
 
490
489
  /** SOUND API */
491
490
  /**
492
- * Play a predefined sound or a ZzFX array of params.
493
- * By default has 4 predefined sounds.
491
+ * Play a sound made using ZzFX library.
492
+ * If the first argument is omitted, plays an default sound.
493
+ *
494
+ * @param {number|number[]} [sound] a ZzFX array of params
495
+ * @param {number} [volume] the volume factor
496
+ * @param {number} [pitch] a value to increment/decrement the pitch
497
+ * @param {number} [randomness] an float between 0 and 1
494
498
  *
495
- * @param {number|number[]} [sound=0] the sound index (from 0 to 3) or a ZzFX array of params
496
- * @param {number} [volume=1] the volume factor
497
- * @param {number} [pitch=0] a value to increment/decrement the pitch
498
- * @param {number} [randomness=null] an float between 0 and 1
499
- * @returns {AudioBufferSourceNode}
500
499
  * @see https://github.com/KilledByAPixel/ZzFX
501
- * @see https://github.com/litecanvas/game-engine/blob/main/src/sounds.js
502
500
  */
503
501
  sfx(
504
- sound?: number | number[],
502
+ sound?: number[],
505
503
  volume?: number,
506
504
  pitch?: number,
507
505
  randomness?: number
508
- ): AudioBufferSourceNode
506
+ ): void
507
+ /**
508
+ * Set the ZzFX's global volume.
509
+ * default: `0.3`
510
+ *
511
+ * @param {number} value
512
+ */
513
+ volume(value: number): void
509
514
 
510
515
  /** UTILS API */
511
516
  /**
@@ -695,10 +700,6 @@ type LitecanvasPluginHelpers = {
695
700
  * The instance color palette (writable)
696
701
  */
697
702
  colors: string[]
698
- /**
699
- * The instance ZzFX sounds (writable)
700
- */
701
- sounds: number[][]
702
703
  /**
703
704
  * An instance settings/options (read-only)
704
705
  */
package/src/sounds.js DELETED
@@ -1,11 +0,0 @@
1
- // prettier-ignore
2
- export const sounds = [
3
- // 0 - pickup
4
- [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
5
- // 1 - hit
6
- [0.7, , 820, , , , , 1.5, , 0.3, , 0.1, 1.6, , , 0.1, 0.2],
7
- // 2 - jump
8
- [0.7, , 360, 0.01, , 0.08, 1, 1.7, 12, 32, , , , , , , , 0.63, 0.02, , 99],
9
- // 3 - powerup
10
- [, , 300, 0.02, 0.1, , 1, 3.2, , , 100, 0.08, 0.1, , , , , 0.6, 0.25, 0.3],
11
- ]