litecanvas 0.54.0 → 0.55.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.js CHANGED
@@ -1,6 +1,7 @@
1
1
  (() => {
2
2
  // src/zzfx.js
3
3
  var zzfxX = /* @__PURE__ */ new AudioContext();
4
+ globalThis.zzfxV = 1;
4
5
  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) => {
5
6
  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;
6
7
  e = R * e + 9;
@@ -13,7 +14,7 @@
13
14
  v *= d / R;
14
15
  z *= R;
15
16
  l = R * l | 0;
16
- p *= globalThis.zzfxV || 0.3;
17
+ p *= globalThis.zzfxV * 0.3;
17
18
  for (h = e + m + r + t + c | 0; a < h; k[a++] = f * p)
18
19
  ++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);
19
20
  p = zzfxX.createBuffer(1, h, R);
@@ -42,7 +43,7 @@
42
43
 
43
44
  // src/index.js
44
45
  function litecanvas(settings = {}) {
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 = {
46
+ const root = globalThis, PI = Math.PI, TWO_PI = PI * 2, on = (elem, evt, callback) => elem.addEventListener(evt, callback), defaults = {
46
47
  fps: 60,
47
48
  fullscreen: true,
48
49
  width: null,
@@ -85,6 +86,8 @@
85
86
  CENTERX: null,
86
87
  /** @type {number} */
87
88
  CENTERY: null,
89
+ /** @type {number[]} */
90
+ DEFAULT_SFX: [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
88
91
  /** MATH API */
89
92
  /**
90
93
  * The value of the mathematical constant PI (π).
@@ -409,10 +412,10 @@
409
412
  * @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
410
413
  */
411
414
  paint(width, height, draw, options = {}) {
412
- const offscreenCanvas = new OffscreenCanvas(width, height), ctxOriginal = _ctx, scale = options.scale || 1;
413
- offscreenCanvas.width = width * scale;
414
- offscreenCanvas.height = height * scale;
415
- _ctx = offscreenCanvas.getContext("2d");
415
+ const oc = options.canvas || new OffscreenCanvas(0, 0), scale = options.scale || 1, contextBackup = _ctx;
416
+ oc.width = width * scale;
417
+ oc.height = height * scale;
418
+ _ctx = oc.getContext("2d");
416
419
  _ctx.scale(scale, scale);
417
420
  if (Array.isArray(draw)) {
418
421
  let x = 0, y = 0;
@@ -428,10 +431,10 @@
428
431
  x = 0;
429
432
  }
430
433
  } else {
431
- draw(offscreenCanvas, _ctx);
434
+ draw(oc, _ctx);
432
435
  }
433
- _ctx = ctxOriginal;
434
- return offscreenCanvas;
436
+ _ctx = contextBackup;
437
+ return oc;
435
438
  },
436
439
  /** ADVANCED GRAPHICS API */
437
440
  /**
@@ -441,7 +444,7 @@
441
444
  * @returns {CanvasRenderingContext2D}
442
445
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
443
446
  */
444
- ctx: (context) => {
447
+ ctx(context) {
445
448
  if (context) {
446
449
  _ctx = context;
447
450
  }
@@ -576,37 +579,37 @@
576
579
  },
577
580
  /** SOUND API */
578
581
  /**
579
- * Play a sound made using ZzFX library.
582
+ * Play a sound effects using ZzFX library.
580
583
  * If the first argument is omitted, plays an default sound.
581
584
  *
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
585
+ * @param {number|number[]} [zzfxParams] a ZzFX array of params
586
+ * @param {number} [pitchSlide] a value to increment/decrement the pitch
587
+ * @param {number} [volumeFactor] the volume factor
588
+ * @returns {number[] | boolean} The sound that was played or `false`
586
589
  *
587
590
  * @see https://github.com/KilledByAPixel/ZzFX
588
591
  */
589
- sfx(zzfxParams, volume, pitch, randomness) {
590
- if (navigator.userActivation && !navigator.userActivation.hasBeenActive) {
591
- return;
592
+ sfx(zzfxParams, pitchSlide = 0, volumeFactor = 1) {
593
+ if (root.zzfxV <= 0 || navigator.userActivation && !navigator.userActivation.hasBeenActive) {
594
+ return false;
592
595
  }
593
- zzfxParams = zzfxParams || DEFAULT_SFX_SOUND;
594
- if (volume || pitch || randomness) {
596
+ zzfxParams = zzfxParams || instance.DEFAULT_SFX;
597
+ if (pitchSlide > 0 || volumeFactor !== 1) {
595
598
  zzfxParams = zzfxParams.slice();
596
- zzfxParams[0] = (volume || 1) * (zzfxParams[0] || 1);
597
- zzfxParams[1] = +randomness ? randomness : zzfxParams[1];
598
- zzfxParams[10] = ~~zzfxParams[10] + ~~pitch;
599
+ zzfxParams[0] = volumeFactor * (zzfxParams[0] || 1);
600
+ zzfxParams[10] = ~~zzfxParams[10] + pitchSlide;
599
601
  }
600
602
  zzfx.apply(0, zzfxParams);
603
+ return zzfxParams;
601
604
  },
602
605
  /**
603
- * Set the ZzFX's global volume.
604
- * default: `0.3`
606
+ * Set the ZzFX's global volume factor.
607
+ * Note: use 0 to mute all sound effects.
605
608
  *
606
609
  * @param {number} value
607
610
  */
608
611
  volume(value) {
609
- root.zzfxV = +value || 1;
612
+ root.zzfxV = +value;
610
613
  },
611
614
  /** UTILS API */
612
615
  /**
package/dist/dist.min.js CHANGED
@@ -1 +1 @@
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}})();
1
+ (()=>{var e=/* @__PURE__ */new AudioContext;globalThis.zzfxV=1;var 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,T=1,x=0,b=0,E=0)=>{let H=Math,D=2*H.PI,y=c*=500*D/44100/44100,w=l*=(1-a+2*a*H.random(a=[]))*D/44100,I=0,A=0,P=0,S=1,C=0,z=0,W=0,X=E<0?-1:1,O=D*X*E*2/44100,_=H.cos(O),B=H.sin,F=B(O)/4,L=1+F,Y=-2*_/L,k=(1-F)/L,G=(1+X*_)/2/L,M=-(X+_)/L,R=0,N=0,j=0,V=0;for(n=44100*n+9,x*=44100,i*=44100,r*=44100,v*=44100,f*=500*D/85766121e6,h*=D/44100,p*=D/44100,u*=44100,g=44100*g|0,t*=.3*globalThis.zzfxV,X=n+x+i+r+v|0;P<X;a[P++]=W*t)++z%(100*m|0)||(W=o?1<o?2<o?3<o?B(I*I):H.max(H.min(H.tan(I),1),-1):1-(2*I/D%2+2)%2:1-4*H.abs(H.round(I/D)-I/D):B(I),W=(g?1-b+b*B(D*P/g):1)*(W<0?-1:1)*H.abs(W)**s*(P<n?P/n:P<n+x?1-(P-n)/x*(1-T):P<n+x+i?T:P<X-v?(X-P-v)/r*T:0),W=v?W/2+(v>P?0:(P<X-v?1:(X-P)/v)*a[P-v|0]/2/t):W,E&&(W=V=G*R+M*(R=N)+G*(N=W)-k*j-Y*(j=V))),I+=(O=(l+=c+=f)*H.cos(h*A++))+O*d*B(P**5),S&&++S>u&&(l+=p,w+=p,S=0),!g||++C%g||(l=w,c=y,S=S||1);(t=e.createBuffer(1,X,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=(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 o=!1,s=[],c=e.canvas||document.createElement("canvas"),f=e.fullscreen,p=e.autoscale,u=1,g,d,h,m=1,v,T=1/e.fps,x=1e3*T,b=0,E,H=0,D=0,y="sans-serif",w="",I=32,A=Date.now(),P={init:!1,update:!1,draw:!1,resized:!1,tap:!1,untap:!1,tapping:!1,tapped:!1},S={settings:Object.assign({},e),colors:a},C={WIDTH:e.width,HEIGHT:e.height||e.width,CANVAS:null,ELAPSED:0,FPS:e.fps,CENTERX:null,CENTERY:null,DEFAULT_SFX:[.5,,1675,,.06,.2,1,1.8,,,637,.06],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?C.clamp(r,l,n):r},norm:(e,t,a)=>C.map(e,t,a,0,1),rand:(e=0,t=1)=>(A=(1664525*A+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>C.floor(C.rand()*(t-e+1)+e),seed:e=>null==e?A:A=~~e,cls(e){null==e?h.clearRect(0,0,C.WIDTH,C.HEIGHT):C.rectfill(0,0,C.WIDTH,C.HEIGHT,e)},rect(e,t,a,l,n=0,i=null){h.beginPath(),h[i?"roundRect":"rect"](~~e,~~t,a,l,i),C.stroke(n)},rectfill(e,t,a,l,n=0,i=null){h.beginPath(),h[i?"roundRect":"rect"](~~e,~~t,a,l,i),C.fill(n)},circ(e,t,a,l){h.beginPath(),h.arc(~~e,~~t,a,0,i),h.closePath(),C.stroke(l)},circfill(e,t,a,l){h.beginPath(),h.arc(~~e,~~t,a,0,i),h.closePath(),C.fill(l)},line(e,t,a,l,n){h.beginPath(),h.moveTo(~~e,~~t),h.lineTo(~~a,~~l),C.stroke(n)},linewidth(e){h.lineWidth=e},linedash(e,t=0){h.setLineDash(Array.isArray(e)?e:[e]),h.lineDashOffset=t},text(e,t,a,l=3){h.font=`${w||""} ${I}px ${y}`,h.fillStyle=C.getcolor(l),h.fillText(a,~~e,~~t)},textfont(e){y=e},textsize(e){I=e},textstyle(e){w=e},textalign(e,t){e&&(h.textAlign=e),t&&(h.textBaseline=t)},textmetrics(e,t){h.font=`${w||""} ${t||I}px ${y}`;let a=h.measureText(e);return a.height=a.actualBoundingBoxAscent+a.actualBoundingBoxDescent,a},image(e,t,a){h.drawImage(a,~~e,~~t)},paint(e,t,a,l={}){let n=l.canvas||new OffscreenCanvas(0,0),i=l.scale||1,r=h;if(n.width=e*i,n.height=t*i,(h=n.getContext("2d")).scale(i,i),Array.isArray(a)){let e=0,t=0;for(let l of(h.imageSmoothingEnabled=!1,a)){for(let a of l)" "!==a&&"."!==a&&C.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(n,h);return h=r,n},ctx:e=>(e&&(h=e),h),push:()=>h.save(),pop:()=>h.restore(),translate:(e,t)=>h.translate(~~e,~~t),scale:(e,t)=>h.scale(e,t||e),rotate:e=>h.rotate(e),transform:(e,t,a,l,n,i,r=!0)=>h[r?"setTransform":"transform"](e,t,a,l,n,i),alpha(e){h.globalAlpha=C.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){h.fillStyle=C.getcolor(e),h.fill(t)},stroke(e,t){h.strokeStyle=C.getcolor(e),t?h.stroke(t):h.stroke()},cliprect(e,t,a,l){h.beginPath(),h.rect(e,t,a,l),h.clip()},clipcirc(e,t,a){h.beginPath(),h.arc(e,t,a,0,i),h.clip()},blendmode(e){h.globalCompositeOperation=e},sfx:(e,a=0,n=1)=>!(l.zzfxV<=0)&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||C.DEFAULT_SFX,(a>0||1!==n)&&((e=e.slice())[0]=n*(e[0]||1),e[10]=~~e[10]+a),t.apply(0,e),e),volume(e){l.zzfxV=+e},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:()=>[g,d],timescale(e){m=e},use(e,t={}){e.__conf=t,o?_(e):s.push(e)},listen:(e,t)=>(P[e]=P[e]||[],P[e].push(t),()=>{P[e]=P[e].filter(e=>t!==e)}),emit(e,t,a,l,n){O("before:"+e,t,a,l,n),O(e,t,a,l,n),O("after:"+e,t,a,l,n)},getcolor:e=>a[~~e%a.length],setvar(t,a){C[t]=a,e.global&&(l[t]=a)},resize(e,t){C.setvar("WIDTH",c.width=e),C.setvar("HEIGHT",c.height=t||e),X()}};for(let e of["sin","cos","atan2","hypot","tan","abs","ceil","round","floor","trunc","min","max","pow","sqrt","sign","exp"])C[e]=Math[e];function z(){o=!0,c="string"==typeof c?document.querySelector(c):c,C.setvar("CANVAS",c),h=c.getContext("2d"),C.WIDTH>0&&(f=!1),c.width=C.WIDTH,c.height=C.HEIGHT||C.WIDTH,c.parentNode||document.body.appendChild(c),c.style.display="block",f?(c.style.position="absolute",c.style.inset=0):p&&(c.style.margin="auto");let t=e.loop?e.loop:l;for(let e of Object.keys(P))t[e]&&C.listen(e,t[e]);for(let e of s)_(e);if(r(l,"resize",X),X(),e.tapEvents){let e=(e,t)=>[(e-c.offsetLeft)/u,(t-c.offsetTop)/u],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,o=!1;r(c,"mousedown",t=>{t.preventDefault();let[l,n]=e(t.pageX,t.pageY);C.emit("tap",l,n,0),a(0,l,n),o=!0}),r(c,"mousemove",t=>{t.preventDefault();let[a,l]=[g,d]=e(t.pageX,t.pageY);o&&(C.emit("tapping",a,l,0),n(0,a,l))}),r(c,"mouseup",a=>{a.preventDefault();let l=t.get(0),[n,r]=e(a.pageX,a.pageY);i(l)&&C.emit("tapped",l.startX,l.startY,0),C.emit("untap",n,r,0),t.delete(0),o=!1}),r(c,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l.pageX,l.pageY);C.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),r(c,"touchmove",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,l]=e(a.pageX,a.pageY);C.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)&&C.emit("tapped",l.startX,l.startY,e),C.emit("untap",l.x,l.y,e),t.delete(e))};r(c,"touchend",s),r(c,"touchcancel",s),r(l,"blur",()=>{if(o=!1,0!==t.size)for(let[e,a]of t)C.emit("untap",a.x,a.y,e),t.delete(e)})}e.pauseOnBlur&&(r(l,"blur",()=>{E=null}),r(l,"focus",()=>{E||(v=performance.now(),E=requestAnimationFrame(W))})),C.emit("init"),v=performance.now(),E=requestAnimationFrame(W)}function W(e){let t=0,a=e-v;for(v=e,b+=a;b>=x;)C.emit("update",T*m),C.setvar("ELAPSED",C.ELAPSED+T*m),b-=x,t++;t&&(C.textalign("start","top"),C.emit("draw"),H++,(D+=x*t)+b>=1e3&&(C.setvar("FPS",H),H=0,D-=1e3)),E&&(E=requestAnimationFrame(W))}function X(){let t=l.innerWidth,a=l.innerHeight;f?(C.setvar("WIDTH",c.width=t),C.setvar("HEIGHT",c.height=a)):p&&(u=Math.min(t/C.WIDTH,a/C.HEIGHT),u=e.pixelart?Math.floor(u):u,c.style.width=C.WIDTH*u+"px",c.style.height=C.HEIGHT*u+"px"),C.setvar("CENTERX",C.WIDTH/2),C.setvar("CENTERY",C.HEIGHT/2),(!e.antialias||e.pixelart)&&(h.imageSmoothingEnabled=!1,c.style.imageRendering="pixelated"),C.emit("resized",u)}function O(e,t,a,l,n){if(P[e])for(let i of P[e])i(t,a,l,n)}function _(e){let t=e(C,S,e.__conf);if("object"==typeof t)for(let[e,a]of Object.entries(t))C.setvar(e,a)}if(e.global){if(l.__litecanvas)throw"Cannot instantiate litecanvas globally twice";Object.assign(l,C),l.__litecanvas=C}return"loading"===document.readyState?r(l,"DOMContentLoaded",z):z(),C}})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.54.0",
3
+ "version": "0.55.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
@@ -12,7 +12,6 @@ export default function litecanvas(settings = {}) {
12
12
  const root = globalThis,
13
13
  PI = Math.PI,
14
14
  TWO_PI = PI * 2,
15
- DEFAULT_SFX_SOUND = [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
16
15
  /** @type {(elem:HTMLElement, evt:string, callback:(event:Event)=>void)=>void} */
17
16
  on = (elem, evt, callback) => elem.addEventListener(evt, callback),
18
17
  /** @type {LitecanvasOptions} */
@@ -103,19 +102,28 @@ export default function litecanvas(settings = {}) {
103
102
  const instance = {
104
103
  /** @type {number} */
105
104
  WIDTH: settings.width,
105
+
106
106
  /** @type {number} */
107
107
  HEIGHT: settings.height || settings.width,
108
+
108
109
  /** @type {HTMLCanvasElement} */
109
110
  CANVAS: null,
111
+
110
112
  /** @type {number} */
111
113
  ELAPSED: 0,
114
+
112
115
  /** @type {number} */
113
116
  FPS: settings.fps,
117
+
114
118
  /** @type {number} */
115
119
  CENTERX: null,
120
+
116
121
  /** @type {number} */
117
122
  CENTERY: null,
118
123
 
124
+ /** @type {number[]} */
125
+ DEFAULT_SFX: [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
126
+
119
127
  /** MATH API */
120
128
  /**
121
129
  * The value of the mathematical constant PI (π).
@@ -476,13 +484,13 @@ export default function litecanvas(settings = {}) {
476
484
  * @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
477
485
  */
478
486
  paint(width, height, draw, options = {}) {
479
- const offscreenCanvas = new OffscreenCanvas(width, height),
480
- ctxOriginal = _ctx,
481
- scale = options.scale || 1
487
+ const oc = options.canvas || new OffscreenCanvas(0, 0),
488
+ scale = options.scale || 1,
489
+ contextBackup = _ctx
482
490
 
483
- offscreenCanvas.width = width * scale
484
- offscreenCanvas.height = height * scale
485
- _ctx = offscreenCanvas.getContext('2d')
491
+ oc.width = width * scale
492
+ oc.height = height * scale
493
+ _ctx = oc.getContext('2d')
486
494
 
487
495
  _ctx.scale(scale, scale)
488
496
 
@@ -505,12 +513,12 @@ export default function litecanvas(settings = {}) {
505
513
  x = 0
506
514
  }
507
515
  } else {
508
- draw(offscreenCanvas, _ctx)
516
+ draw(oc, _ctx)
509
517
  }
510
518
 
511
- _ctx = ctxOriginal // restore the context
519
+ _ctx = contextBackup // restore the context
512
520
 
513
- return offscreenCanvas
521
+ return oc
514
522
  },
515
523
 
516
524
  /** ADVANCED GRAPHICS API */
@@ -521,7 +529,7 @@ export default function litecanvas(settings = {}) {
521
529
  * @returns {CanvasRenderingContext2D}
522
530
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
523
531
  */
524
- ctx: (context) => {
532
+ ctx(context) {
525
533
  if (context) {
526
534
  _ctx = context
527
535
  }
@@ -671,46 +679,47 @@ export default function litecanvas(settings = {}) {
671
679
 
672
680
  /** SOUND API */
673
681
  /**
674
- * Play a sound made using ZzFX library.
682
+ * Play a sound effects using ZzFX library.
675
683
  * If the first argument is omitted, plays an default sound.
676
684
  *
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
685
+ * @param {number|number[]} [zzfxParams] a ZzFX array of params
686
+ * @param {number} [pitchSlide] a value to increment/decrement the pitch
687
+ * @param {number} [volumeFactor] the volume factor
688
+ * @returns {number[] | boolean} The sound that was played or `false`
681
689
  *
682
690
  * @see https://github.com/KilledByAPixel/ZzFX
683
691
  */
684
- sfx(zzfxParams, volume, pitch, randomness) {
692
+ sfx(zzfxParams, pitchSlide = 0, volumeFactor = 1) {
685
693
  if (
686
- navigator.userActivation &&
687
- !navigator.userActivation.hasBeenActive
694
+ root.zzfxV <= 0 ||
695
+ (navigator.userActivation &&
696
+ !navigator.userActivation.hasBeenActive)
688
697
  ) {
689
- return
698
+ return false
690
699
  }
691
700
 
692
- // prettier-ignore
693
- zzfxParams = zzfxParams || DEFAULT_SFX_SOUND
701
+ zzfxParams = zzfxParams || instance.DEFAULT_SFX
694
702
 
695
703
  // if has other arguments, copy the sound to not change the original
696
- if (volume || pitch || randomness) {
704
+ if (pitchSlide > 0 || volumeFactor !== 1) {
697
705
  zzfxParams = zzfxParams.slice()
698
- zzfxParams[0] = (volume || 1) * (zzfxParams[0] || 1)
699
- zzfxParams[1] = +randomness ? randomness : zzfxParams[1]
700
- zzfxParams[10] = ~~zzfxParams[10] + ~~pitch
706
+ zzfxParams[0] = volumeFactor * (zzfxParams[0] || 1)
707
+ zzfxParams[10] = ~~zzfxParams[10] + pitchSlide
701
708
  }
702
709
 
703
710
  zzfx.apply(0, zzfxParams)
711
+
712
+ return zzfxParams
704
713
  },
705
714
 
706
715
  /**
707
- * Set the ZzFX's global volume.
708
- * default: `0.3`
716
+ * Set the ZzFX's global volume factor.
717
+ * Note: use 0 to mute all sound effects.
709
718
  *
710
719
  * @param {number} value
711
720
  */
712
721
  volume(value) {
713
- root.zzfxV = +value || 1
722
+ root.zzfxV = +value
714
723
  },
715
724
 
716
725
  /** UTILS API */
package/src/zzfx.js CHANGED
@@ -1,5 +1,8 @@
1
1
  // ZzFXMicro - Zuper Zmall Zound Zynth - v1.3.0 by Frank Force | https://github.com/KilledByAPixel/ZzFX
2
2
  const zzfxX = /** @__PURE__ */ new AudioContext()
3
+
4
+ globalThis.zzfxV = 1
5
+
3
6
  export const zzfx = (
4
7
  p = 1,
5
8
  k = 0.05,
@@ -60,7 +63,7 @@ export const zzfx = (
60
63
  v *= d / R
61
64
  z *= R
62
65
  l = (R * l) | 0
63
- p *= globalThis.zzfxV || 0.3
66
+ p *= globalThis.zzfxV * 0.3
64
67
  for (h = (e + m + r + t + c) | 0; a < h; k[a++] = f * p)
65
68
  ++J % ((100 * F) | 0) ||
66
69
  ((f = q
package/types/index.d.ts CHANGED
@@ -24,6 +24,8 @@ declare global {
24
24
  var CENTERX: number
25
25
  /** the center Y of the game screen */
26
26
  var CENTERY: number
27
+ /** the default `sfx()` sound */
28
+ var DEFAULT_SFX: number[]
27
29
 
28
30
  /** MATH API */
29
31
  /**
@@ -505,25 +507,24 @@ declare global {
505
507
 
506
508
  /** SOUND API */
507
509
  /**
508
- * Play a sound made using ZzFX library.
510
+ * Play a sound effects using ZzFX library.
509
511
  * If the first argument is omitted, plays an default sound.
510
512
  *
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
513
+ * @param {number|number[]} [zzfxParams] a ZzFX array of params
514
+ * @param {number} [pitchSlide] a value to increment/decrement the pitch
515
+ * @param {number} [volumeFactor] the volume factor
516
+ * @returns The sound that was played or `false`
515
517
  *
516
518
  * @see https://github.com/KilledByAPixel/ZzFX
517
519
  */
518
520
  function sfx(
519
- sound?: number[],
520
- volume?: number,
521
- pitch?: number,
522
- randomness?: number
523
- ): void
521
+ zzfxParams?: number[],
522
+ pitchSlide?: number = 0,
523
+ volumeFactor?: number = 1
524
+ ): number[] | boolean
524
525
  /**
525
- * Set the ZzFX's global volume.
526
- * default: `0.3`
526
+ * Set the ZzFX's global volume factor.
527
+ * Note: use 0 to mute all sound effects.
527
528
  *
528
529
  * @param {number} value
529
530
  */
package/types/types.d.ts CHANGED
@@ -13,6 +13,8 @@ type LitecanvasInstance = {
13
13
  CENTERX: number
14
14
  /** the center Y of the game screen */
15
15
  CENTERY: number
16
+ /** the default `sfx()` sound */
17
+ DEFAULT_SFX: number[]
16
18
 
17
19
  /** MATH API */
18
20
  /**
@@ -488,25 +490,24 @@ type LitecanvasInstance = {
488
490
 
489
491
  /** SOUND API */
490
492
  /**
491
- * Play a sound made using ZzFX library.
493
+ * Play a sound effects using ZzFX library.
492
494
  * If the first argument is omitted, plays an default sound.
493
495
  *
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
496
+ * @param {number|number[]} [zzfxParams] a ZzFX array of params
497
+ * @param {number} [pitchSlide] a value to increment/decrement the pitch
498
+ * @param {number} [volumeFactor] the volume factor
499
+ * @returns The sound that was played or `false`
498
500
  *
499
501
  * @see https://github.com/KilledByAPixel/ZzFX
500
502
  */
501
503
  sfx(
502
- sound?: number[],
503
- volume?: number,
504
- pitch?: number,
505
- randomness?: number
506
- ): void
504
+ zzfxParams?: number[],
505
+ pitchSlide?: number = 0,
506
+ volumeFactor?: number = 1
507
+ ): number[] | boolean
507
508
  /**
508
- * Set the ZzFX's global volume.
509
- * default: `0.3`
509
+ * Set the ZzFX's global volume factor.
510
+ * Note: use 0 to mute all sound effects.
510
511
  *
511
512
  * @param {number} value
512
513
  */