litecanvas 0.63.0 → 0.65.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
@@ -1,10 +1,10 @@
1
1
  ![icon2](https://github.com/user-attachments/assets/28b92806-cb70-41c7-be72-12e658eb7819)
2
2
 
3
- # litecanvas
3
+ # Litecanvas
4
4
 
5
5
  [![Discord Server](https://img.shields.io/badge/Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.com/invite/r2c3rGsvH3)
6
6
 
7
- Litecanvas is a lightweight HTML5 canvas engine suitable for small games, animations and creative programming for people who enjoy coding.
7
+ Litecanvas is a lightweight HTML5 canvas engine suitable for small web games, prototypes, game jams, animations, creative programming, learning game programming and game design, etc.
8
8
 
9
9
  :warning: **This project is still under development. All feedback is appreciated!** :warning:
10
10
 
package/dist/dist.js CHANGED
@@ -30,13 +30,13 @@
30
30
  "#6a7799",
31
31
  "#aec2c2",
32
32
  "#FFF1E8",
33
- "#d82800",
33
+ "#e83b3b",
34
34
  "#f8d878",
35
35
  "#155fd9",
36
36
  "#3cbcfc",
37
37
  "#327345",
38
38
  "#63c64d",
39
- "#6844fc",
39
+ "#6c2c1f",
40
40
  "#ac7c00"
41
41
  ];
42
42
 
@@ -59,7 +59,7 @@
59
59
  animate: true
60
60
  };
61
61
  settings = Object.assign(defaults, settings);
62
- let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _fullscreen = settings.fullscreen, _autoscale = settings.autoscale, _animate = settings.animate, _scale = 1, _ctx, _timeScale = 1, _lastFrame, _step = 1 / settings.fps, _stepMs = _step * 1e3, _accumulated = 0, _focused = true, _drawCount = 0, _drawTime = 0, _fontFamily = "sans-serif", _fontStyle = "", _fontSize = 32, _rng_seed = Date.now(), _events = {
62
+ let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _fullscreen = settings.fullscreen, _autoscale = settings.autoscale, _animate = settings.animate, _scale = 1, _ctx, _timeScale = 1, _lastFrame, _step, _stepMs, _accumulated = 0, _focused = true, _drawCount = 0, _drawTime = 0, _fontFamily = "sans-serif", _fontStyle = "", _fontSize = 32, _rng_seed = Date.now(), _events = {
63
63
  init: false,
64
64
  update: false,
65
65
  draw: false,
@@ -175,9 +175,9 @@
175
175
  * @param {boolean} [withinBounds=false] constrain the value to the newly mapped range
176
176
  * @returns {number} the remapped number
177
177
  */
178
- map(value, min1, max1, min2, max2, withinBounds = false) {
178
+ map(value, min1, max1, min2, max2, withinBounds) {
179
179
  const result = (value - min1) / (max1 - min1) * (max2 - min2) + min2;
180
- return !withinBounds ? result : instance.clamp(result, min2, max2);
180
+ return withinBounds ? instance.clamp(result, min2, max2) : result;
181
181
  },
182
182
  /**
183
183
  * Maps a number from one range to a value between 0 and 1.
@@ -320,13 +320,13 @@
320
320
  /**
321
321
  * Sets the line dash pattern used when drawing lines
322
322
  *
323
- * @param {number|number[]} segments the line dash pattern
323
+ * @param {number[]} segments the line dash pattern
324
324
  * @param {number} [offset=0] the line dash offset, or "phase".
325
325
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
326
326
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
327
327
  */
328
328
  linedash(segments, offset = 0) {
329
- _ctx.setLineDash(Array.isArray(segments) ? segments : [segments]);
329
+ _ctx.setLineDash(segments);
330
330
  _ctx.lineDashOffset = offset;
331
331
  },
332
332
  /** TEXT RENDERING API */
@@ -410,7 +410,9 @@
410
410
  * @param {number} width
411
411
  * @param {number} height
412
412
  * @param {string[]|drawCallback} draw
413
- * @param {{scale?:number}} [options]
413
+ * @param {object} [options]
414
+ * @param {number} [options.scale]
415
+ * @param {OffscreenCanvas | HTMLCanvasElement} [options.canvas]
414
416
  * @returns {OffscreenCanvas}
415
417
  * @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
416
418
  */
@@ -420,7 +422,7 @@
420
422
  canvas.height = height * scale;
421
423
  _ctx = canvas.getContext("2d");
422
424
  _ctx.scale(scale, scale);
423
- if (Array.isArray(draw)) {
425
+ if (draw.pop) {
424
426
  let x = 0, y = 0;
425
427
  _ctx.imageSmoothingEnabled = false;
426
428
  for (const str of draw) {
@@ -559,7 +561,7 @@
559
561
  * Play a sound effects using ZzFX library.
560
562
  * If the first argument is omitted, plays an default sound.
561
563
  *
562
- * @param {number|number[]} [zzfxParams] a ZzFX array of params
564
+ * @param {number[]} [zzfxParams] a ZzFX array of params
563
565
  * @param {number} [pitchSlide] a value to increment/decrement the pitch
564
566
  * @param {number} [volumeFactor] the volume factor
565
567
  * @returns {number[] | boolean} The sound that was played or `false`
@@ -615,16 +617,6 @@
615
617
  * @returns {boolean}
616
618
  */
617
619
  colcirc: (x1, y1, r1, x2, y2, r2) => (x2 - x1) ** 2 + (y2 - y1) ** 2 <= (r1 + r2) ** 2,
618
- /**
619
- * The scale of the game's delta time (dt).
620
- * Values higher than 1 increase the speed of time, while values smaller than 1 decrease it.
621
- * A value of 0 freezes time and is effectively equivalent to pausing.
622
- *
623
- * @param {number} value
624
- */
625
- timescale(value) {
626
- _timeScale = value;
627
- },
628
620
  /** PLUGINS API */
629
621
  /**
630
622
  * Prepares a plugin to be loaded
@@ -694,6 +686,26 @@
694
686
  instance.setvar("WIDTH", _canvas.width = width);
695
687
  instance.setvar("HEIGHT", _canvas.height = height || width);
696
688
  pageResized();
689
+ },
690
+ /**
691
+ * The scale of the game's delta time (dt).
692
+ * Values higher than 1 increase the speed of time, while values smaller than 1 decrease it.
693
+ * A value of 0 freezes time and is effectively equivalent to pausing.
694
+ *
695
+ * @param {number} value
696
+ */
697
+ timescale(value) {
698
+ _timeScale = value;
699
+ },
700
+ /**
701
+ * Set the target FPS at runtime.
702
+ *
703
+ * @param {number} fps
704
+ */
705
+ setfps(fps) {
706
+ _step = 1 / fps;
707
+ _stepMs = _step * 1e3;
708
+ _accumulated = 0;
697
709
  }
698
710
  };
699
711
  for (const k of [
@@ -843,12 +855,13 @@
843
855
  _focused = true;
844
856
  });
845
857
  }
858
+ instance.setfps(settings.fps);
846
859
  instance.emit("init", instance);
847
860
  _lastFrame = performance.now();
848
861
  raf(drawFrame);
849
862
  }
850
863
  function drawFrame(now) {
851
- let ticks = 0, t = now - _lastFrame;
864
+ let ticks = _animate ? 0 : 1, t = now - _lastFrame;
852
865
  _lastFrame = now;
853
866
  _accumulated += t;
854
867
  while (_accumulated > _stepMs) {
@@ -857,7 +870,7 @@
857
870
  _accumulated -= _stepMs;
858
871
  ticks++;
859
872
  }
860
- if (ticks || !_animate) {
873
+ if (ticks) {
861
874
  instance.textalign("start", "top");
862
875
  instance.emit("draw");
863
876
  _drawCount++;
package/dist/dist.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e=/* @__PURE__ */new AudioContext,t=(t=1,a=.05,l=220,n=0,r=0,i=.1,o=0,s=1,c=0,f=0,p=0,u=0,d=0,g=0,h=0,m=0,v=0,T=1,x=0,E=0,y=0)=>{let b=Math,w=2*b.PI,H=c*=500*w/44100/44100,D=l*=(1-a+2*a*b.random(a=[]))*w/44100,I=0,A=0,S=0,k=1,C=0,O=0,P=0,X=y<0?-1:1,L=w*X*y*2/44100,W=b.cos(L),z=b.sin,Y=z(L)/4,F=1+Y,M=-2*W/F,_=(1-Y)/F,B=(1+X*W)/2/F,G=-(X+W)/F,R=0,N=0,j=0,U=0;for(n=44100*n+9,x*=44100,r*=44100,i*=44100,v*=44100,f*=500*w/85766121e6,h*=w/44100,p*=w/44100,u*=44100,d=44100*d|0,t*=.3*(globalThis.zzfxV||1),X=n+x+r+i+v|0;S<X;a[S++]=P*t)++O%(100*m|0)||(P=o?1<o?2<o?3<o?z(I*I):b.max(b.min(b.tan(I),1),-1):1-(2*I/w%2+2)%2:1-4*b.abs(b.round(I/w)-I/w):z(I),P=(d?1-E+E*z(w*S/d):1)*(P<0?-1:1)*b.abs(P)**s*(S<n?S/n:S<n+x?1-(S-n)/x*(1-T):S<n+x+r?T:S<X-v?(X-S-v)/i*T:0),P=v?P/2+(v>S?0:(S<X-v?1:(X-S)/v)*a[S-v|0]/2/t):P,y&&(P=U=B*R+G*(R=N)+B*(N=P)-_*j-M*(j=U))),I+=(L=(l+=c+=f)*b.cos(h*A++))+L*g*z(S**5),k&&++k>u&&(l+=p,D+=p,k=0),!d||++C%d||(l=D,c=H,k=k||1);(t=e.createBuffer(1,X,44100)).getChannelData(0).set(a),(l=e.createBufferSource()).buffer=t,l.connect(e.destination),l.start()},a=["#111","#6a7799","#aec2c2","#FFF1E8","#d82800","#f8d878","#155fd9","#3cbcfc","#327345","#63c64d","#6844fc","#ac7c00"];globalThis.litecanvas=function(e={}){let l=globalThis,n=Math.PI,r=2*n,i=requestAnimationFrame,o=(e,t,a)=>e.addEventListener(t,a);e=Object.assign({fps:60,fullscreen:!0,width:null,height:null,autoscale:!0,pixelart:!1,antialias:!1,canvas:null,global:!0,loop:null,pauseOnBlur:!0,tapEvents:!0,keyboardEvents:!0,animate:!0},e);let s=!1,c=[],f=e.canvas||document.createElement("canvas"),p=e.fullscreen,u=e.autoscale,d=e.animate,g=1,h,m=1,v,T=1/e.fps,x=1e3*T,E=0,y=!0,b=0,w=0,H="sans-serif",D="",I=32,A=Date.now(),S={init:!1,update:!1,draw:!1,resized:!1,tap:!1,untap:!1,tapping:!1,tapped:!1},k={settings:Object.assign({},e),colors:a},C={WIDTH:e.width,HEIGHT:e.height||e.width,CANVAS:null,ELAPSED:0,FPS:e.fps,CENTERX:0,CENTERY:0,MOUSEX:-1,MOUSEY:-1,DEFAULT_SFX:[.5,,1675,,.06,.2,1,1.8,,,637,.06],PI:n,TWO_PI:r,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,r=!1){let i=(e-t)/(a-t)*(n-l)+l;return r?C.clamp(i,l,n):i},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(e,t+1)),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,r=null){h.beginPath(),h[r?"roundRect":"rect"](~~e,~~t,a,l,r),C.stroke(n)},rectfill(e,t,a,l,n=0,r=null){h.beginPath(),h[r?"roundRect":"rect"](~~e,~~t,a,l,r),C.fill(n)},circ(e,t,a,l){h.beginPath(),h.arc(~~e,~~t,a,0,r),C.stroke(l)},circfill(e,t,a,l){h.beginPath(),h.arc(~~e,~~t,a,0,r),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=`${D} ${I}px ${H}`,h.fillStyle=C.getcolor(l),h.fillText(a,~~e,~~t)},textfont(e){H=e},textsize(e){I=e},textstyle(e){D=e||""},textalign(e,t){e&&(h.textAlign=e),t&&(h.textBaseline=t)},textmetrics(e,t=I){h.font=`${D} ${t}px ${H}`;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(1,1),r=l.scale||1,i=h;if(n.width=e*r,n.height=t*r,(h=n.getContext("2d")).scale(r,r),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(h);return h=i,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,r,i=!0)=>h[i?"setTransform":"transform"](e,t,a,l,n,r),alpha(e){h.globalAlpha=C.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){h.fillStyle=C.getcolor(e),t?h.fill(t):h.fill()},stroke(e,t){h.strokeStyle=C.getcolor(e),t?h.stroke(t):h.stroke()},clip(e){h.clip(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,r,i,o)=>e<n+i&&e+a>n&&t<r+o&&t+l>r,colcirc:(e,t,a,l,n,r)=>(l-e)**2+(n-t)**2<=(a+r)**2,timescale(e){m=e},use(e,t={}){e.__conf=t,s?W(e):c.push(e)},listen:(e,t)=>(S[e]=S[e]||[],S[e].push(t),()=>{S[e]=S[e].filter(e=>t!==e)}),emit(e,t,a,l,n){L("before:"+e,t,a,l,n),L(e,t,a,l,n),L("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",f.width=e),C.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"])C[e]=Math[e];function O(){s=!0,f="string"==typeof f?document.querySelector(f):f,C.setvar("CANVAS",f),h=f.getContext("2d"),C.WIDTH>0&&(p=!1),f.width=C.WIDTH,f.height=C.HEIGHT||C.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(S))t[e]&&C.listen(e,t[e]);for(let e of c)W(e);if(o(l,"resize",X),X(),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 r=t.get(e)||a(e);r.x=l,r.y=n},r=e=>e&&performance.now()-e.ts<=200,i=!1;o(f,"mousedown",t=>{t.preventDefault();let[l,n]=e(t.pageX,t.pageY);C.emit("tap",l,n,0),a(0,l,n),i=!0}),o(f,"mousemove",t=>{t.preventDefault();let[a,l]=e(t.pageX,t.pageY);C.setvar("MOUSEX",a),C.setvar("MOUSEY",l),i&&(C.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);r(l)&&C.emit("tapped",l.startX,l.startY,0),C.emit("untap",n,o,0),t.delete(0),i=!1}),o(f,"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)}}),o(f,"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)||(r(l)&&C.emit("tapped",l.startX,l.startY,e),C.emit("untap",l.x,l.y,e),t.delete(e))};o(f,"touchend",s),o(f,"touchcancel",s),o(l,"blur",()=>{for(let[e,a]of(i=!1,t))C.emit("untap",a.x,a.y,e),t.delete(e)})}if(e.keyboardEvents){let e=/* @__PURE__ */new Set;C.setvar("iskeydown",t=>"any"===t?e.size>0:e.has(t.toLowerCase())),o(l,"keydown",t=>{e.add(t.key.toLowerCase())}),o(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),o(l,"blur",()=>e.clear())}e.pauseOnBlur&&(o(l,"blur",()=>{y=!1}),o(l,"focus",()=>{v=performance.now(),i(P),y=!0})),C.emit("init",C),v=performance.now(),i(P)}function P(e){let t=0,a=e-v;for(v=e,E+=a;E>x;)C.emit("update",T*m),C.setvar("ELAPSED",C.ELAPSED+T*m),E-=x,t++;(t||!d)&&(C.textalign("start","top"),C.emit("draw"),b++,(w+=x*t)+E>=1e3&&(C.setvar("FPS",b),b=0,w-=1e3)),y&&d&&i(P)}function X(){let t=l.innerWidth,a=l.innerHeight;p?(C.setvar("WIDTH",f.width=t),C.setvar("HEIGHT",f.height=a)):u&&(g=Math.min(t/C.WIDTH,a/C.HEIGHT),g=(e.pixelart?~~g:g)||1,f.style.width=C.WIDTH*g+"px",f.style.height=C.HEIGHT*g+"px"),C.setvar("CENTERX",C.WIDTH/2),C.setvar("CENTERY",C.HEIGHT/2),(!e.antialias||e.pixelart)&&(h.imageSmoothingEnabled=!1,f.style.imageRendering="pixelated"),C.emit("resized",g),d||i(P)}function L(e,t,a,l,n){if(S[e])for(let r of S[e])r(t,a,l,n)}function W(e){let t=e(C,k,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"global litecanvas already instantiated";Object.assign(l,C),l.__litecanvas=C}return"loading"===document.readyState?o(l,"DOMContentLoaded",O):O(),C}})();
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,d=0,g=0,h=0,m=0,v=0,T=1,x=0,E=0,b=0)=>{let y=Math,w=2*y.PI,H=c*=500*w/44100/44100,D=l*=(1-a+2*a*y.random(a=[]))*w/44100,I=0,S=0,A=0,k=1,C=0,O=0,P=0,X=b<0?-1:1,L=w*X*b*2/44100,W=y.cos(L),z=y.sin,Y=z(L)/4,F=1+Y,M=-2*W/F,_=(1-Y)/F,B=(1+X*W)/2/F,G=-(X+W)/F,R=0,N=0,j=0,U=0;for(n=44100*n+9,x*=44100,i*=44100,r*=44100,v*=44100,f*=500*w/85766121e6,h*=w/44100,p*=w/44100,u*=44100,d=44100*d|0,t*=.3*(globalThis.zzfxV||1),X=n+x+i+r+v|0;A<X;a[A++]=P*t)++O%(100*m|0)||(P=o?1<o?2<o?3<o?z(I*I):y.max(y.min(y.tan(I),1),-1):1-(2*I/w%2+2)%2:1-4*y.abs(y.round(I/w)-I/w):z(I),P=(d?1-E+E*z(w*A/d):1)*(P<0?-1:1)*y.abs(P)**s*(A<n?A/n:A<n+x?1-(A-n)/x*(1-T):A<n+x+i?T:A<X-v?(X-A-v)/r*T:0),P=v?P/2+(v>A?0:(A<X-v?1:(X-A)/v)*a[A-v|0]/2/t):P,b&&(P=U=B*R+G*(R=N)+B*(N=P)-_*j-M*(j=U))),I+=(L=(l+=c+=f)*y.cos(h*S++))+L*g*z(A**5),k&&++k>u&&(l+=p,D+=p,k=0),!d||++C%d||(l=D,c=H,k=k||1);(t=e.createBuffer(1,X,44100)).getChannelData(0).set(a),(l=e.createBufferSource()).buffer=t,l.connect(e.destination),l.start()},a=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#f8d878","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(e={}){let l=globalThis,n=Math.PI,i=2*n,r=requestAnimationFrame,o=(e,t,a)=>e.addEventListener(t,a);e=Object.assign({fps:60,fullscreen:!0,width:null,height:null,autoscale:!0,pixelart:!1,antialias:!1,canvas:null,global:!0,loop:null,pauseOnBlur:!0,tapEvents:!0,keyboardEvents:!0,animate:!0},e);let s=!1,c=[],f=e.canvas||document.createElement("canvas"),p=e.fullscreen,u=e.autoscale,d=e.animate,g=1,h,m=1,v,T,x,E=0,b=!0,y=0,w=0,H="sans-serif",D="",I=32,S=Date.now(),A={init:!1,update:!1,draw:!1,resized:!1,tap:!1,untap:!1,tapping:!1,tapped:!1},k={settings:Object.assign({},e),colors:a},C={WIDTH:e.width,HEIGHT:e.height||e.width,CANVAS:null,ELAPSED:0,FPS:e.fps,CENTERX:0,CENTERY:0,MOUSEX:-1,MOUSEY:-1,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){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)=>(S=(1664525*S+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>C.floor(C.rand(e,t+1)),seed:e=>null==e?S:S=~~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),C.stroke(l)},circfill(e,t,a,l){h.beginPath(),h.arc(~~e,~~t,a,0,i),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(e),h.lineDashOffset=t},text(e,t,a,l=3){h.font=`${D} ${I}px ${H}`,h.fillStyle=C.getcolor(l),h.fillText(a,~~e,~~t)},textfont(e){H=e},textsize(e){I=e},textstyle(e){D=e||""},textalign(e,t){e&&(h.textAlign=e),t&&(h.textBaseline=t)},textmetrics(e,t=I){h.font=`${D} ${t}px ${H}`;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(1,1),i=l.scale||1,r=h;if(n.width=e*i,n.height=t*i,(h=n.getContext("2d")).scale(i,i),a.pop){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(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),t?h.fill(t):h.fill()},stroke(e,t){h.strokeStyle=C.getcolor(e),t?h.stroke(t):h.stroke()},clip(e){h.clip(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,use(e,t={}){e.__conf=t,s?W(e):c.push(e)},listen:(e,t)=>(A[e]=A[e]||[],A[e].push(t),()=>{A[e]=A[e].filter(e=>t!==e)}),emit(e,t,a,l,n){L("before:"+e,t,a,l,n),L(e,t,a,l,n),L("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",f.width=e),C.setvar("HEIGHT",f.height=t||e),X()},timescale(e){m=e},setfps(e){x=1e3*(T=1/e),E=0}};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 O(){s=!0,f="string"==typeof f?document.querySelector(f):f,C.setvar("CANVAS",f),h=f.getContext("2d"),C.WIDTH>0&&(p=!1),f.width=C.WIDTH,f.height=C.HEIGHT||C.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(A))t[e]&&C.listen(e,t[e]);for(let e of c)W(e);if(o(l,"resize",X),X(),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);C.emit("tap",l,n,0),a(0,l,n),r=!0}),o(f,"mousemove",t=>{t.preventDefault();let[a,l]=e(t.pageX,t.pageY);C.setvar("MOUSEX",a),C.setvar("MOUSEY",l),r&&(C.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)&&C.emit("tapped",l.startX,l.startY,0),C.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);C.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);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))};o(f,"touchend",s),o(f,"touchcancel",s),o(l,"blur",()=>{for(let[e,a]of(r=!1,t))C.emit("untap",a.x,a.y,e),t.delete(e)})}if(e.keyboardEvents){let e=/* @__PURE__ */new Set;C.setvar("iskeydown",t=>"any"===t?e.size>0:e.has(t.toLowerCase())),o(l,"keydown",t=>{e.add(t.key.toLowerCase())}),o(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),o(l,"blur",()=>e.clear())}e.pauseOnBlur&&(o(l,"blur",()=>{b=!1}),o(l,"focus",()=>{v=performance.now(),r(P),b=!0})),C.setfps(e.fps),C.emit("init",C),v=performance.now(),r(P)}function P(e){let t=d?0:1,a=e-v;for(v=e,E+=a;E>x;)C.emit("update",T*m),C.setvar("ELAPSED",C.ELAPSED+T*m),E-=x,t++;t&&(C.textalign("start","top"),C.emit("draw"),y++,(w+=x*t)+E>=1e3&&(C.setvar("FPS",y),y=0,w-=1e3)),b&&d&&r(P)}function X(){let t=l.innerWidth,a=l.innerHeight;p?(C.setvar("WIDTH",f.width=t),C.setvar("HEIGHT",f.height=a)):u&&(g=Math.min(t/C.WIDTH,a/C.HEIGHT),g=(e.pixelart?~~g:g)||1,f.style.width=C.WIDTH*g+"px",f.style.height=C.HEIGHT*g+"px"),C.setvar("CENTERX",C.WIDTH/2),C.setvar("CENTERY",C.HEIGHT/2),(!e.antialias||e.pixelart)&&(h.imageSmoothingEnabled=!1,f.style.imageRendering="pixelated"),C.emit("resized",g),d||r(P)}function L(e,t,a,l,n){if(A[e])for(let i of A[e])i(t,a,l,n)}function W(e){let t=e(C,k,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"global litecanvas already instantiated";Object.assign(l,C),l.__litecanvas=C}return"loading"===document.readyState?o(l,"DOMContentLoaded",O):O(),C}})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.63.0",
3
+ "version": "0.65.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
@@ -57,9 +57,9 @@ export default function litecanvas(settings = {}) {
57
57
  /** @type {number} */
58
58
  _lastFrame,
59
59
  /** @type {number} */
60
- _step = 1 / settings.fps,
60
+ _step,
61
61
  /** @type {number} */
62
- _stepMs = _step * 1000,
62
+ _stepMs,
63
63
  /** @type {number} */
64
64
  _accumulated = 0,
65
65
  /** @type {number} */
@@ -222,10 +222,10 @@ export default function litecanvas(settings = {}) {
222
222
  * @param {boolean} [withinBounds=false] constrain the value to the newly mapped range
223
223
  * @returns {number} the remapped number
224
224
  */
225
- map(value, min1, max1, min2, max2, withinBounds = false) {
225
+ map(value, min1, max1, min2, max2, withinBounds) {
226
226
  // prettier-ignore
227
227
  const result = ((value - min1) / (max1 - min1)) * (max2 - min2) + min2
228
- return !withinBounds ? result : instance.clamp(result, min2, max2)
228
+ return withinBounds ? instance.clamp(result, min2, max2) : result
229
229
  },
230
230
 
231
231
  /**
@@ -383,13 +383,13 @@ export default function litecanvas(settings = {}) {
383
383
  /**
384
384
  * Sets the line dash pattern used when drawing lines
385
385
  *
386
- * @param {number|number[]} segments the line dash pattern
386
+ * @param {number[]} segments the line dash pattern
387
387
  * @param {number} [offset=0] the line dash offset, or "phase".
388
388
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
389
389
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
390
390
  */
391
391
  linedash(segments, offset = 0) {
392
- _ctx.setLineDash(Array.isArray(segments) ? segments : [segments])
392
+ _ctx.setLineDash(segments)
393
393
  _ctx.lineDashOffset = offset
394
394
  },
395
395
 
@@ -484,7 +484,9 @@ export default function litecanvas(settings = {}) {
484
484
  * @param {number} width
485
485
  * @param {number} height
486
486
  * @param {string[]|drawCallback} draw
487
- * @param {{scale?:number}} [options]
487
+ * @param {object} [options]
488
+ * @param {number} [options.scale]
489
+ * @param {OffscreenCanvas | HTMLCanvasElement} [options.canvas]
488
490
  * @returns {OffscreenCanvas}
489
491
  * @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
490
492
  */
@@ -499,8 +501,8 @@ export default function litecanvas(settings = {}) {
499
501
 
500
502
  _ctx.scale(scale, scale)
501
503
 
502
- // is pixelart?
503
- if (Array.isArray(draw)) {
504
+ // draw pixel art if `draw` is a array
505
+ if (draw.pop) {
504
506
  let x = 0,
505
507
  y = 0
506
508
 
@@ -661,7 +663,7 @@ export default function litecanvas(settings = {}) {
661
663
  * Play a sound effects using ZzFX library.
662
664
  * If the first argument is omitted, plays an default sound.
663
665
  *
664
- * @param {number|number[]} [zzfxParams] a ZzFX array of params
666
+ * @param {number[]} [zzfxParams] a ZzFX array of params
665
667
  * @param {number} [pitchSlide] a value to increment/decrement the pitch
666
668
  * @param {number} [volumeFactor] the volume factor
667
669
  * @returns {number[] | boolean} The sound that was played or `false`
@@ -732,17 +734,6 @@ export default function litecanvas(settings = {}) {
732
734
  colcirc: (x1, y1, r1, x2, y2, r2) =>
733
735
  (x2 - x1) ** 2 + (y2 - y1) ** 2 <= (r1 + r2) ** 2,
734
736
 
735
- /**
736
- * The scale of the game's delta time (dt).
737
- * Values higher than 1 increase the speed of time, while values smaller than 1 decrease it.
738
- * A value of 0 freezes time and is effectively equivalent to pausing.
739
- *
740
- * @param {number} value
741
- */
742
- timescale(value) {
743
- _timeScale = value
744
- },
745
-
746
737
  /** PLUGINS API */
747
738
  /**
748
739
  * Prepares a plugin to be loaded
@@ -820,6 +811,28 @@ export default function litecanvas(settings = {}) {
820
811
  instance.setvar('HEIGHT', (_canvas.height = height || width))
821
812
  pageResized()
822
813
  },
814
+
815
+ /**
816
+ * The scale of the game's delta time (dt).
817
+ * Values higher than 1 increase the speed of time, while values smaller than 1 decrease it.
818
+ * A value of 0 freezes time and is effectively equivalent to pausing.
819
+ *
820
+ * @param {number} value
821
+ */
822
+ timescale(value) {
823
+ _timeScale = value
824
+ },
825
+
826
+ /**
827
+ * Set the target FPS at runtime.
828
+ *
829
+ * @param {number} fps
830
+ */
831
+ setfps(fps) {
832
+ _step = 1 / fps
833
+ _stepMs = _step * 1000
834
+ _accumulated = 0
835
+ },
823
836
  }
824
837
 
825
838
  /** Copy some functions from native `Math` object */
@@ -1021,6 +1034,8 @@ export default function litecanvas(settings = {}) {
1021
1034
  })
1022
1035
  }
1023
1036
 
1037
+ instance.setfps(settings.fps)
1038
+
1024
1039
  // start the game loop
1025
1040
  instance.emit('init', instance)
1026
1041
 
@@ -1032,7 +1047,7 @@ export default function litecanvas(settings = {}) {
1032
1047
  * @param {number} now
1033
1048
  */
1034
1049
  function drawFrame(now) {
1035
- let ticks = 0,
1050
+ let ticks = _animate ? 0 : 1,
1036
1051
  t = now - _lastFrame
1037
1052
 
1038
1053
  _lastFrame = now
@@ -1045,7 +1060,7 @@ export default function litecanvas(settings = {}) {
1045
1060
  ticks++
1046
1061
  }
1047
1062
 
1048
- if (ticks || !_animate) {
1063
+ if (ticks) {
1049
1064
  // default values for textAlign & textBaseline
1050
1065
  instance.textalign('start', 'top')
1051
1066
 
package/src/palette.js CHANGED
@@ -1,17 +1,16 @@
1
- // Default colors inspired by https://lospec.com/palette-list/trirampo
2
1
  export const colors = [
3
2
  '#111',
4
3
  '#6a7799',
5
4
  '#aec2c2',
6
5
  '#FFF1E8',
7
6
 
8
- '#d82800',
7
+ '#e83b3b',
9
8
  '#f8d878',
10
9
  '#155fd9',
11
10
  '#3cbcfc',
12
11
 
13
12
  '#327345',
14
13
  '#63c64d',
15
- '#6844fc',
14
+ '#6c2c1f',
16
15
  '#ac7c00',
17
16
  ]