litecanvas 0.205.0 → 0.206.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dist.dev.js CHANGED
@@ -115,7 +115,7 @@
115
115
  var assert = (condition, message = "Assertion failed") => {
116
116
  if (!condition) throw new Error("[litecanvas] " + message);
117
117
  };
118
- var version = "0.205.0";
118
+ var version = "0.206.0";
119
119
  function litecanvas(settings = {}) {
120
120
  const root = window,
121
121
  math = Math,
@@ -147,7 +147,7 @@
147
147
  };
148
148
  settings = Object.assign(defaults, settings);
149
149
  let _initialized = false,
150
- _paused = true,
150
+ _paused,
151
151
  _canvas,
152
152
  _canvasScale = 1,
153
153
  _ctx,
@@ -156,7 +156,7 @@
156
156
  _lastFrameTime,
157
157
  _fpsInterval = 1e3 / 60,
158
158
  _accumulated,
159
- _rafid,
159
+ _rafid = 0,
160
160
  _defaultTextColor = 3,
161
161
  _fontFamily = "sans-serif",
162
162
  _fontSize = 20,
@@ -165,8 +165,6 @@
165
165
  _colorPalette = defaultPalette,
166
166
  _colorPaletteState = [],
167
167
  _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1],
168
- _mathFunctions =
169
- "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp",
170
168
  _eventListeners = {};
171
169
  const instance = {
172
170
  W: 0,
@@ -1033,7 +1031,7 @@
1033
1031
  pause() {
1034
1032
  if (!_paused) {
1035
1033
  _paused = true;
1036
- cancelAnimationFrame(_rafid);
1034
+ _rafid = ~~cancelAnimationFrame(_rafid);
1037
1035
  instance.emit("paused");
1038
1036
  }
1039
1037
  },
@@ -1044,10 +1042,8 @@
1044
1042
  'resume() cannot be called before the "init" event and neither after the quit() function',
1045
1043
  );
1046
1044
  if (_initialized && _paused) {
1045
+ startGameLoop();
1047
1046
  _paused = false;
1048
- _accumulated = _fpsInterval;
1049
- _lastFrameTime = perf.now();
1050
- _rafid = raf(drawFrame);
1051
1047
  instance.emit("resumed");
1052
1048
  }
1053
1049
  },
@@ -1073,9 +1069,18 @@
1073
1069
  );
1074
1070
  },
1075
1071
  };
1076
- for (const k of _mathFunctions.split(",")) {
1072
+ const mathProps =
1073
+ "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp";
1074
+ for (const k of mathProps.split(",")) {
1077
1075
  instance[k] = math[k];
1078
1076
  }
1077
+ function startGameLoop() {
1078
+ if (!_rafid) {
1079
+ _accumulated = 0;
1080
+ _lastFrameTime = perf.now();
1081
+ _rafid = raf(drawFrame);
1082
+ }
1083
+ }
1079
1084
  function init() {
1080
1085
  if (settings.autoscale) {
1081
1086
  on(root, "resize", resizeCanvas);
@@ -1216,8 +1221,10 @@
1216
1221
  instance.def("lastkey", () => _lastKey);
1217
1222
  }
1218
1223
  _initialized = true;
1219
- instance.resume();
1220
1224
  instance.emit("init", instance);
1225
+ if (!_paused) {
1226
+ startGameLoop();
1227
+ }
1221
1228
  }
1222
1229
  function drawFrame() {
1223
1230
  _rafid = raf(drawFrame);
@@ -1237,18 +1244,13 @@
1237
1244
  instance.emit("draw", _ctx);
1238
1245
  if (updated > 1) {
1239
1246
  _accumulated = 0;
1240
- DEV: console.warn(
1241
- loggerPrefix +
1242
- "the last frame updated " +
1243
- updated +
1244
- " times. This can drop the FPS if it keeps happening.",
1245
- );
1246
1247
  }
1247
1248
  }
1248
1249
  }
1249
1250
  function setupCanvas() {
1251
+ const d = document;
1250
1252
  if ("string" === typeof settings.canvas) {
1251
- _canvas = document.querySelector(settings.canvas);
1253
+ _canvas = d.querySelector(settings.canvas);
1252
1254
  DEV: assert(
1253
1255
  null != _canvas,
1254
1256
  loggerPrefix +
@@ -1257,7 +1259,7 @@
1257
1259
  } else {
1258
1260
  _canvas = settings.canvas;
1259
1261
  }
1260
- _canvas = _canvas || document.createElement("canvas");
1262
+ _canvas = _canvas || d.createElement("canvas");
1261
1263
  DEV: assert(
1262
1264
  _canvas instanceof HTMLElement && "CANVAS" === _canvas.tagName,
1263
1265
  loggerPrefix +
@@ -1267,7 +1269,7 @@
1267
1269
  on(_canvas, "click", () => focus());
1268
1270
  resizeCanvas();
1269
1271
  if (!_canvas.parentNode) {
1270
- document.body.appendChild(_canvas);
1272
+ d.body.appendChild(_canvas);
1271
1273
  }
1272
1274
  _canvas.style.imageRendering = "pixelated";
1273
1275
  _canvas.oncontextmenu = () => false;
@@ -1351,7 +1353,7 @@
1351
1353
  instance.listen(eventName, settings.loop[eventName]);
1352
1354
  }
1353
1355
  }
1354
- _rafid = raf(init);
1356
+ raf(init);
1355
1357
  return instance;
1356
1358
  }
1357
1359
  window.litecanvas = litecanvas;
package/dist/dist.js CHANGED
@@ -143,7 +143,7 @@
143
143
  };
144
144
  settings = Object.assign(defaults, settings);
145
145
  let _initialized = false,
146
- _paused = true,
146
+ _paused,
147
147
  _canvas,
148
148
  _canvasScale = 1,
149
149
  _ctx,
@@ -152,7 +152,7 @@
152
152
  _lastFrameTime,
153
153
  _fpsInterval = 1e3 / 60,
154
154
  _accumulated,
155
- _rafid,
155
+ _rafid = 0,
156
156
  _defaultTextColor = 3,
157
157
  _fontFamily = "sans-serif",
158
158
  _fontSize = 20,
@@ -161,8 +161,6 @@
161
161
  _colorPalette = defaultPalette,
162
162
  _colorPaletteState = [],
163
163
  _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1],
164
- _mathFunctions =
165
- "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp",
166
164
  _eventListeners = {};
167
165
  const instance = {
168
166
  W: 0,
@@ -482,16 +480,14 @@
482
480
  pause() {
483
481
  if (!_paused) {
484
482
  _paused = true;
485
- cancelAnimationFrame(_rafid);
483
+ _rafid = ~~cancelAnimationFrame(_rafid);
486
484
  instance.emit("paused");
487
485
  }
488
486
  },
489
487
  resume() {
490
488
  if (_initialized && _paused) {
489
+ startGameLoop();
491
490
  _paused = false;
492
- _accumulated = _fpsInterval;
493
- _lastFrameTime = perf.now();
494
- _rafid = raf(drawFrame);
495
491
  instance.emit("resumed");
496
492
  }
497
493
  },
@@ -514,9 +510,18 @@
514
510
  }
515
511
  },
516
512
  };
517
- for (const k of _mathFunctions.split(",")) {
513
+ const mathProps =
514
+ "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp";
515
+ for (const k of mathProps.split(",")) {
518
516
  instance[k] = math[k];
519
517
  }
518
+ function startGameLoop() {
519
+ if (!_rafid) {
520
+ _accumulated = 0;
521
+ _lastFrameTime = perf.now();
522
+ _rafid = raf(drawFrame);
523
+ }
524
+ }
520
525
  function init() {
521
526
  if (settings.autoscale) {
522
527
  on(root, "resize", resizeCanvas);
@@ -647,8 +652,10 @@
647
652
  instance.def("lastkey", () => _lastKey);
648
653
  }
649
654
  _initialized = true;
650
- instance.resume();
651
655
  instance.emit("init", instance);
656
+ if (!_paused) {
657
+ startGameLoop();
658
+ }
652
659
  }
653
660
  function drawFrame() {
654
661
  _rafid = raf(drawFrame);
@@ -672,17 +679,18 @@
672
679
  }
673
680
  }
674
681
  function setupCanvas() {
682
+ const d = document;
675
683
  if ("string" === typeof settings.canvas) {
676
- _canvas = document.querySelector(settings.canvas);
684
+ _canvas = d.querySelector(settings.canvas);
677
685
  } else {
678
686
  _canvas = settings.canvas;
679
687
  }
680
- _canvas = _canvas || document.createElement("canvas");
688
+ _canvas = _canvas || d.createElement("canvas");
681
689
  _ctx = _canvas.getContext("2d");
682
690
  on(_canvas, "click", () => focus());
683
691
  resizeCanvas();
684
692
  if (!_canvas.parentNode) {
685
- document.body.appendChild(_canvas);
693
+ d.body.appendChild(_canvas);
686
694
  }
687
695
  _canvas.style.imageRendering = "pixelated";
688
696
  _canvas.oncontextmenu = () => false;
@@ -742,7 +750,7 @@
742
750
  instance.listen(eventName, settings.loop[eventName]);
743
751
  }
744
752
  }
745
- _rafid = raf(init);
753
+ raf(init);
746
754
  return instance;
747
755
  }
748
756
  window.litecanvas = litecanvas;
package/dist/dist.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e=["#211e20","#555568","#a0a08b","#e9efec"];window.litecanvas=function(t={}){let l,a=window,n=Math,i=performance,o=2*n.PI,r=requestAnimationFrame,s=[],f=(e,t,l)=>{e.addEventListener(t,l,!1),s.push(()=>e.removeEventListener(t,l,!1))},c=(l=new AudioContext,a.zzfxV=1,(e=1,t=.05,n=220,i=0,o=0,r=.1,s=0,f=1,c=0,d=0,p=0,u=0,h=0,m=0,g=0,w=0,v=0,x=1,y=0,b=0,k=0)=>{let E=Math,P=2*E.PI,T=c*=500*P/44100/44100,z=n*=(1-t+2*t*E.random(t=[]))*P/44100,C=0,I=0,L=0,D=1,A=0,S=0,H=0,M=k<0?-1:1,N=P*M*k*2/44100,W=E.cos(N),q=E.sin,B=q(N)/4,V=1+B,O=-2*W/V,R=(1-B)/V,F=(1+M*W)/2/V,G=-(M+W)/V,X=0,Y=0,$=0,j=0;for(i=44100*i+9,y*=44100,o*=44100,r*=44100,v*=44100,d*=500*P/85766121e6,g*=P/44100,p*=P/44100,u*=44100,h=44100*h|0,e*=.3*a.zzfxV,M=i+y+o+r+v|0;L<M;t[L++]=H*e)++S%(100*w|0)||(H=s?1<s?2<s?3<s?q(C*C):E.max(E.min(E.tan(C),1),-1):1-(2*C/P%2+2)%2:1-4*E.abs(E.round(C/P)-C/P):q(C),H=(h?1-b+b*q(P*L/h):1)*(H<0?-1:1)*E.abs(H)**f*(L<i?L/i:L<i+y?1-(L-i)/y*(1-x):L<i+y+o?x:L<M-v?(M-L-v)/r*x:0),H=v?H/2+(v>L?0:(L<M-v?1:(M-L)/v)*t[L-v|0]/2/e):H,k&&(H=j=F*X+G*(X=Y)+F*(Y=H)-R*$-O*($=j))),C+=(N=(n+=c+=d)*E.cos(g*I++))+N*m*q(L**5),D&&++D>u&&(n+=p,z+=p,D=0),!h||++A%h||(n=z,c=T,D=D||1);(e=l.createBuffer(1,M,44100)).getChannelData(0).set(t),(n=l.createBufferSource()).buffer=e,n.connect(l.destination),n.start()});t=Object.assign({width:null,height:null,autoscale:!0,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0},t);let d=!1,p=!0,u,h=1,m,g=.5,w=1,v,x=1e3/60,y,b,k=3,E="sans-serif",P=20,T=1.2,z=Date.now(),C=e,I=[],L=[.5,0,1750,,,.3,1,,,,600,.1],D={},A={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:o,HALF_PI:o/4,lerp:(e,t,l)=>e+l*(t-e),deg2rad:e=>n.PI/180*e,rad2deg:e=>180/n.PI*e,round:(e,t=0)=>{if(!t)return n.round(e);let l=10**t;return n.round(e*l)/l},clamp:(e,t,l)=>e<t?t:e>l?l:e,dist:(e,t,l,a)=>n.hypot(l-e,a-t),wrap:(e,t,l)=>e-(l-t)*n.floor((e-t)/(l-t)),map(e,t,l,a,n,i){let o=(e-t)/(l-t)*(n-a)+a;return i?A.clamp(o,a,n):o},norm:(e,t,l)=>A.map(e,t,l,0,1),rand:(e=0,t=1)=>(z=(1664525*z+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>~~A.rand(e,t+1),rseed(e){z=~~e},cls(e){null==e?m.clearRect(0,0,A.W,A.H):A.rectfill(0,0,A.W,A.H,e)},rect(e,t,l,a,n,i){m.beginPath(),m[i?"roundRect":"rect"](~~e-g,~~t-g,~~l+2*g,~~a+2*g,i),A.stroke(n)},rectfill(e,t,l,a,n,i){m.beginPath(),m[i?"roundRect":"rect"](~~e,~~t,~~l,~~a,i),A.fill(n)},circ(e,t,l,a){m.beginPath(),m.arc(~~e,~~t,~~l,0,o),A.stroke(a)},circfill(e,t,l,a){m.beginPath(),m.arc(~~e,~~t,~~l,0,o),A.fill(a)},oval(e,t,l,a,n){m.beginPath(),m.ellipse(~~e,~~t,~~l,~~a,0,0,o),A.stroke(n)},ovalfill(e,t,l,a,n){m.beginPath(),m.ellipse(~~e,~~t,~~l,~~a,0,0,o),A.fill(n)},shape(e){m.beginPath();for(let t=0;t<e.length;t+=2)0===t?m.moveTo(~~e[t],~~e[t+1]):m.lineTo(~~e[t],~~e[t+1]);m.lineTo(~~e[0],~~e[1])},line(e,t,l,a,n){m.beginPath();let i=.5*(0!==g&&~~e==~~l),o=.5*(0!==g&&~~t==~~a);m.moveTo(~~e+i,~~t+o),m.lineTo(~~l+i,~~a+o),A.stroke(n)},linewidth(e){m.lineWidth=~~e,g=.5*(0!=~~e%2)},linedash(e,t=0){m.setLineDash(e),m.lineDashOffset=t},text(e,t,l,a=k,n="normal"){m.font=`${n} ${P}px ${E}`,m.fillStyle=N(a);let i=(""+l).split("\n");for(let l=0;l<i.length;l++)m.fillText(i[l],~~e,~~t+P*T*l)},textgap(e){T=e},textfont(e){E=e},textsize(e){P=e},textalign(e,t){e&&(m.textAlign=e),t&&(m.textBaseline=t)},image(e,t,l){m.drawImage(l,~~e,~~t)},spr(e,t,l){let a=l.trim().split("\n");for(let l=0;l<a.length;l++){let n=a[l].trim();for(let a=0;a<n.length;a++){let i=n[a];"."!==i&&" "!==i&&A.rectfill(e+a,t+l,1,1,parseInt(i,36)||0)}}},paint(e,t,l,a={}){let n=a.canvas||new OffscreenCanvas(1,1),i=a.scale||1,o=m;return n.width=e*i,n.height=t*i,(m=n.getContext("2d")).scale(i,i),l(m),m=o,n.transferToImageBitmap()},ctx:e=>(e&&(m=e),m),push(){m.save()},pop(){m.restore()},translate(e,t){m.translate(~~e,~~t)},scale(e,t=e){m.scale(e,t)},rotate(e){m.rotate(e)},alpha(e){m.globalAlpha=A.clamp(e,0,1)},fill(e){m.fillStyle=N(e),m.fill()},stroke(e){m.strokeStyle=N(e),m.stroke()},clip(e){m.beginPath(),e(m),m.clip()},sfx:(e,t=0,l=1)=>!!a.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||L,(0!==t||1!==l)&&((e=e.slice())[0]=l*(e[0]||1),e[10]=~~e[10]+t),c.apply(0,e),e),volume(e){a.zzfxV=e},canvas:()=>u,use(e,t={}){var l=e,a=t;let n=l(A,a);for(let e in n)A.def(e,n[e])},listen:(e,t)=>{D[e=e.toLowerCase()]=D[e]||new Set,D[e].add(t)},unlisten:(e,t)=>{D[e=e.toLowerCase()]&&D[e].delete(t)},emit:(e,l,n,i,o)=>(d&&(M("before:"+(e=e.toLowerCase()),l,n,i,o),t.loop||a[e]===A[e]||"function"!=typeof a[e]||a[e](l,n,i,o),M(e,l,n,i,o),M("after:"+e,l,n,i,o)),l),pal(t,l=3){C=t||e,I=[],k=l,A.emit("pal",C,k)},palc(e,t){null==e?I=[]:I[e]=t},def(e,l){A[e]=l,t.global&&(a[e]=l)},timescale(e){w=e},framerate(e){x=1e3/~~e},stat:e=>[t,d,x/1e3,h,D,C,L,w,a.zzfxV,z,P,E,I,T][e],pause(){p||(p=!0,cancelAnimationFrame(b),A.emit("paused"))},resume(){d&&p&&(p=!1,y=x,v=i.now(),b=r(S),A.emit("resumed"))},ispaused:()=>p,quit(){for(let e of(A.emit("quit"),A.pause(),d=!1,D={},s))e();if(t.global){for(let e in A)delete a[e];delete a.ENGINE}}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))A[e]=n[e];function S(){b=r(S);let e=i.now(),t=0,l=e-v;for(v=e,y+=l<100?l:x;y>=x;){t++,y-=x;let e=x/1e3*w;A.emit("update",e,t),A.def("T",A.T+e)}t&&(A.emit("draw",m),t>1&&(y=0))}function H(){let e=t.width>0?t.width:innerWidth,l=t.width>0?t.height||t.width:innerHeight;if(A.def("W",e),A.def("H",l),u.width=e,u.height=l,t.autoscale){let a=+t.autoscale;u.style.display||(u.style.display="block",u.style.margin="auto"),h=n.min(innerWidth/e,innerHeight/l),h=a>1&&h>a?a:h,u.style.width=e*h+"px",u.style.height=l*h+"px"}m.imageSmoothingEnabled=!1,A.textalign("start","top"),A.emit("resized",h)}function M(e,t,l,a,n){if(D[e])for(let i of D[e])i(t,l,a,n)}function N(e){return C[~~(I[e]??e)%C.length]}if(t.global){if(a.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(a,A),a.ENGINE=A}if(m=(u=(u="string"==typeof t.canvas?document.querySelector(t.canvas):t.canvas)||document.createElement("canvas")).getContext("2d"),f(u,"click",()=>focus()),H(),u.parentNode||document.body.appendChild(u),u.style.imageRendering="pixelated",u.oncontextmenu=()=>!1,t.loop)for(let e in t.loop)t.loop[e]&&A.listen(e,t.loop[e]);return b=r(function(){if(t.autoscale&&f(a,"resize",H),t.tapEvents){let e=e=>[(e.pageX-u.offsetLeft)/h,(e.pageY-u.offsetTop)/h],t=new Map,l=(e,l,a)=>{let n={x:l,y:a,xi:l,yi:a,t:i.now()};return t.set(e,n),n},n=(e,a,n)=>{let i=t.get(e)||l(e);i.x=a,i.y=n},o=e=>e&&i.now()-e.t<=300,r=!1;f(u,"mousedown",t=>{if(0===t.button){t.preventDefault();let[a,n]=e(t);A.emit("tap",a,n,0),l(0,a,n),r=!0}}),f(u,"mouseup",l=>{if(0===l.button){l.preventDefault();let a=t.get(0),[n,i]=e(l);o(a)&&A.emit("tapped",a.xi,a.yi,0),A.emit("untap",n,i,0),t.delete(0),r=!1}}),f(a,"mousemove",t=>{t.preventDefault();let[l,a]=e(t);A.def("MX",l),A.def("MY",a),r&&(A.emit("tapping",l,a,0),n(0,l,a))}),f(u,"touchstart",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,n]=e(a);A.emit("tap",t,n,a.identifier+1),l(a.identifier+1,t,n)}}),f(u,"touchmove",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,a]=e(l);A.emit("tapping",t,a,l.identifier+1),n(l.identifier+1,t,a)}});let s=e=>{e.preventDefault();let l=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)l.push(t.identifier+1);for(let[e,a]of t)l.includes(e)||(o(a)&&A.emit("tapped",a.xi,a.yi,e),A.emit("untap",a.x,a.y,e),t.delete(e))};f(u,"touchend",s),f(u,"touchcancel",s),f(a,"blur",()=>{for(let[e,l]of(r=!1,t))A.emit("untap",l.x,l.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,l=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0,n="";f(a,"keydown",l=>{let a=l.key.toLowerCase();e.has(a)||(e.add(a),t.add(a),n=" "===a?"space":a)}),f(a,"keyup",t=>{e.delete(t.key.toLowerCase())}),f(a,"blur",()=>e.clear()),A.listen("after:update",()=>t.clear()),A.def("iskeydown",t=>l(e,t)),A.def("iskeypressed",e=>l(t,e)),A.def("lastkey",()=>n)}d=!0,A.resume(),A.emit("init",A)}),A}})();
1
+ (()=>{var e=["#211e20","#555568","#a0a08b","#e9efec"];window.litecanvas=function(t={}){let l,a,n=window,i=Math,o=performance,r=2*i.PI,s=requestAnimationFrame,f=[],c=(e,t,l)=>{e.addEventListener(t,l,!1),f.push(()=>e.removeEventListener(t,l,!1))},d=(l=new AudioContext,n.zzfxV=1,(e=1,t=.05,a=220,i=0,o=0,r=.1,s=0,f=1,c=0,d=0,p=0,u=0,h=0,m=0,g=0,w=0,v=0,x=1,y=0,b=0,k=0)=>{let E=Math,P=2*E.PI,T=c*=500*P/44100/44100,z=a*=(1-t+2*t*E.random(t=[]))*P/44100,C=0,I=0,L=0,D=1,A=0,S=0,H=0,M=k<0?-1:1,N=P*M*k*2/44100,W=E.cos(N),q=E.sin,B=q(N)/4,V=1+B,O=-2*W/V,R=(1-B)/V,F=(1+M*W)/2/V,G=-(M+W)/V,X=0,Y=0,$=0,j=0;for(i=44100*i+9,y*=44100,o*=44100,r*=44100,v*=44100,d*=500*P/85766121e6,g*=P/44100,p*=P/44100,u*=44100,h=44100*h|0,e*=.3*n.zzfxV,M=i+y+o+r+v|0;L<M;t[L++]=H*e)++S%(100*w|0)||(H=s?1<s?2<s?3<s?q(C*C):E.max(E.min(E.tan(C),1),-1):1-(2*C/P%2+2)%2:1-4*E.abs(E.round(C/P)-C/P):q(C),H=(h?1-b+b*q(P*L/h):1)*(H<0?-1:1)*E.abs(H)**f*(L<i?L/i:L<i+y?1-(L-i)/y*(1-x):L<i+y+o?x:L<M-v?(M-L-v)/r*x:0),H=v?H/2+(v>L?0:(L<M-v?1:(M-L)/v)*t[L-v|0]/2/e):H,k&&(H=j=F*X+G*(X=Y)+F*(Y=H)-R*$-O*($=j))),C+=(N=(a+=c+=d)*E.cos(g*I++))+N*m*q(L**5),D&&++D>u&&(a+=p,z+=p,D=0),!h||++A%h||(a=z,c=T,D=D||1);(e=l.createBuffer(1,M,44100)).getChannelData(0).set(t),(a=l.createBufferSource()).buffer=e,a.connect(l.destination),a.start()});t=Object.assign({width:null,height:null,autoscale:!0,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0},t);let p=!1,u,h,m=1,g,w=.5,v=1,x,y=1e3/60,b,k=0,E=3,P="sans-serif",T=20,z=1.2,C=Date.now(),I=e,L=[],D=[.5,0,1750,,,.3,1,,,,600,.1],A={},S={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:r,HALF_PI:r/4,lerp:(e,t,l)=>e+l*(t-e),deg2rad:e=>i.PI/180*e,rad2deg:e=>180/i.PI*e,round:(e,t=0)=>{if(!t)return i.round(e);let l=10**t;return i.round(e*l)/l},clamp:(e,t,l)=>e<t?t:e>l?l:e,dist:(e,t,l,a)=>i.hypot(l-e,a-t),wrap:(e,t,l)=>e-(l-t)*i.floor((e-t)/(l-t)),map(e,t,l,a,n,i){let o=(e-t)/(l-t)*(n-a)+a;return i?S.clamp(o,a,n):o},norm:(e,t,l)=>S.map(e,t,l,0,1),rand:(e=0,t=1)=>(C=(1664525*C+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>~~S.rand(e,t+1),rseed(e){C=~~e},cls(e){null==e?g.clearRect(0,0,S.W,S.H):S.rectfill(0,0,S.W,S.H,e)},rect(e,t,l,a,n,i){g.beginPath(),g[i?"roundRect":"rect"](~~e-w,~~t-w,~~l+2*w,~~a+2*w,i),S.stroke(n)},rectfill(e,t,l,a,n,i){g.beginPath(),g[i?"roundRect":"rect"](~~e,~~t,~~l,~~a,i),S.fill(n)},circ(e,t,l,a){g.beginPath(),g.arc(~~e,~~t,~~l,0,r),S.stroke(a)},circfill(e,t,l,a){g.beginPath(),g.arc(~~e,~~t,~~l,0,r),S.fill(a)},oval(e,t,l,a,n){g.beginPath(),g.ellipse(~~e,~~t,~~l,~~a,0,0,r),S.stroke(n)},ovalfill(e,t,l,a,n){g.beginPath(),g.ellipse(~~e,~~t,~~l,~~a,0,0,r),S.fill(n)},shape(e){g.beginPath();for(let t=0;t<e.length;t+=2)0===t?g.moveTo(~~e[t],~~e[t+1]):g.lineTo(~~e[t],~~e[t+1]);g.lineTo(~~e[0],~~e[1])},line(e,t,l,a,n){g.beginPath();let i=.5*(0!==w&&~~e==~~l),o=.5*(0!==w&&~~t==~~a);g.moveTo(~~e+i,~~t+o),g.lineTo(~~l+i,~~a+o),S.stroke(n)},linewidth(e){g.lineWidth=~~e,w=.5*(0!=~~e%2)},linedash(e,t=0){g.setLineDash(e),g.lineDashOffset=t},text(e,t,l,a=E,n="normal"){g.font=`${n} ${T}px ${P}`,g.fillStyle=q(a);let i=(""+l).split("\n");for(let l=0;l<i.length;l++)g.fillText(i[l],~~e,~~t+T*z*l)},textgap(e){z=e},textfont(e){P=e},textsize(e){T=e},textalign(e,t){e&&(g.textAlign=e),t&&(g.textBaseline=t)},image(e,t,l){g.drawImage(l,~~e,~~t)},spr(e,t,l){let a=l.trim().split("\n");for(let l=0;l<a.length;l++){let n=a[l].trim();for(let a=0;a<n.length;a++){let i=n[a];"."!==i&&" "!==i&&S.rectfill(e+a,t+l,1,1,parseInt(i,36)||0)}}},paint(e,t,l,a={}){let n=a.canvas||new OffscreenCanvas(1,1),i=a.scale||1,o=g;return n.width=e*i,n.height=t*i,(g=n.getContext("2d")).scale(i,i),l(g),g=o,n.transferToImageBitmap()},ctx:e=>(e&&(g=e),g),push(){g.save()},pop(){g.restore()},translate(e,t){g.translate(~~e,~~t)},scale(e,t=e){g.scale(e,t)},rotate(e){g.rotate(e)},alpha(e){g.globalAlpha=S.clamp(e,0,1)},fill(e){g.fillStyle=q(e),g.fill()},stroke(e){g.strokeStyle=q(e),g.stroke()},clip(e){g.beginPath(),e(g),g.clip()},sfx:(e,t=0,l=1)=>!!n.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||D,(0!==t||1!==l)&&((e=e.slice())[0]=l*(e[0]||1),e[10]=~~e[10]+t),d.apply(0,e),e),volume(e){n.zzfxV=e},canvas:()=>h,use(e,t={}){var l=e,a=t;let n=l(S,a);for(let e in n)S.def(e,n[e])},listen:(e,t)=>{A[e=e.toLowerCase()]=A[e]||new Set,A[e].add(t)},unlisten:(e,t)=>{A[e=e.toLowerCase()]&&A[e].delete(t)},emit:(e,l,a,i,o)=>(p&&(W("before:"+(e=e.toLowerCase()),l,a,i,o),t.loop||n[e]===S[e]||"function"!=typeof n[e]||n[e](l,a,i,o),W(e,l,a,i,o),W("after:"+e,l,a,i,o)),l),pal(t,l=3){I=t||e,L=[],E=l,S.emit("pal",I,E)},palc(e,t){null==e?L=[]:L[e]=t},def(e,l){S[e]=l,t.global&&(n[e]=l)},timescale(e){v=e},framerate(e){y=1e3/~~e},stat:e=>[t,p,y/1e3,m,A,I,D,v,n.zzfxV,C,T,P,L,z][e],pause(){u||(u=!0,k=~~cancelAnimationFrame(k),S.emit("paused"))},resume(){p&&u&&(H(),u=!1,S.emit("resumed"))},ispaused:()=>u,quit(){for(let e of(S.emit("quit"),S.pause(),p=!1,A={},f))e();if(t.global){for(let e in S)delete n[e];delete n.ENGINE}}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))S[e]=i[e];function H(){k||(b=0,x=o.now(),k=s(M))}function M(){k=s(M);let e=o.now(),t=0,l=e-x;for(x=e,b+=l<100?l:y;b>=y;){t++,b-=y;let e=y/1e3*v;S.emit("update",e,t),S.def("T",S.T+e)}t&&(S.emit("draw",g),t>1&&(b=0))}function N(){let e=t.width>0?t.width:innerWidth,l=t.width>0?t.height||t.width:innerHeight;if(S.def("W",e),S.def("H",l),h.width=e,h.height=l,t.autoscale){let a=+t.autoscale;h.style.display||(h.style.display="block",h.style.margin="auto"),m=i.min(innerWidth/e,innerHeight/l),m=a>1&&m>a?a:m,h.style.width=e*m+"px",h.style.height=l*m+"px"}g.imageSmoothingEnabled=!1,S.textalign("start","top"),S.emit("resized",m)}function W(e,t,l,a,n){if(A[e])for(let i of A[e])i(t,l,a,n)}function q(e){return I[~~(L[e]??e)%I.length]}if(t.global){if(n.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(n,S),n.ENGINE=S}if(a=document,g=(h=(h="string"==typeof t.canvas?a.querySelector(t.canvas):t.canvas)||a.createElement("canvas")).getContext("2d"),c(h,"click",()=>focus()),N(),h.parentNode||a.body.appendChild(h),h.style.imageRendering="pixelated",h.oncontextmenu=()=>!1,t.loop)for(let e in t.loop)t.loop[e]&&S.listen(e,t.loop[e]);return s(function(){if(t.autoscale&&c(n,"resize",N),t.tapEvents){let e=e=>[(e.pageX-h.offsetLeft)/m,(e.pageY-h.offsetTop)/m],t=new Map,l=(e,l,a)=>{let n={x:l,y:a,xi:l,yi:a,t:o.now()};return t.set(e,n),n},a=(e,a,n)=>{let i=t.get(e)||l(e);i.x=a,i.y=n},i=e=>e&&o.now()-e.t<=300,r=!1;c(h,"mousedown",t=>{if(0===t.button){t.preventDefault();let[a,n]=e(t);S.emit("tap",a,n,0),l(0,a,n),r=!0}}),c(h,"mouseup",l=>{if(0===l.button){l.preventDefault();let a=t.get(0),[n,o]=e(l);i(a)&&S.emit("tapped",a.xi,a.yi,0),S.emit("untap",n,o,0),t.delete(0),r=!1}}),c(n,"mousemove",t=>{t.preventDefault();let[l,n]=e(t);S.def("MX",l),S.def("MY",n),r&&(S.emit("tapping",l,n,0),a(0,l,n))}),c(h,"touchstart",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,n]=e(a);S.emit("tap",t,n,a.identifier+1),l(a.identifier+1,t,n)}}),c(h,"touchmove",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l);S.emit("tapping",t,n,l.identifier+1),a(l.identifier+1,t,n)}});let s=e=>{e.preventDefault();let l=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)l.push(t.identifier+1);for(let[e,a]of t)l.includes(e)||(i(a)&&S.emit("tapped",a.xi,a.yi,e),S.emit("untap",a.x,a.y,e),t.delete(e))};c(h,"touchend",s),c(h,"touchcancel",s),c(n,"blur",()=>{for(let[e,l]of(r=!1,t))S.emit("untap",l.x,l.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,l=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0,a="";c(n,"keydown",l=>{let n=l.key.toLowerCase();e.has(n)||(e.add(n),t.add(n),a=" "===n?"space":n)}),c(n,"keyup",t=>{e.delete(t.key.toLowerCase())}),c(n,"blur",()=>e.clear()),S.listen("after:update",()=>t.clear()),S.def("iskeydown",t=>l(e,t)),S.def("iskeypressed",e=>l(t,e)),S.def("lastkey",()=>a)}p=!0,S.emit("init",S),u||H()}),S}})();
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.205.0",
3
+ "version": "0.206.0",
4
4
  "description": "Lightweight HTML5 canvas 2D game engine suitable for small projects and creative coding. Inspired by PICO-8 and p5.js/Processing.",
5
5
  "license": "MIT",
6
6
  "author": "Luiz Bills <luizbills@pm.me>",
7
7
  "contributors": [],
8
- "homepage": "https://litecanvas.github.io",
8
+ "homepage": "https://litecanvas.js.org",
9
9
  "repository": {
10
10
  "type": "git",
11
11
  "url": "git+https://github.com/litecanvas/game-engine.git"
@@ -34,7 +34,7 @@
34
34
  "devDependencies": {
35
35
  "@happy-dom/global-registrator": "^20.9.0",
36
36
  "@size-limit/preset-small-lib": "^12.1.0",
37
- "@swc/core": "^1.15.30",
37
+ "@swc/core": "^1.15.32",
38
38
  "ava": "^7.0.0",
39
39
  "esbuild": "^0.27.7",
40
40
  "genversion": "^3.2.0",
package/src/index.js CHANGED
@@ -51,7 +51,7 @@ export default function litecanvas(settings = {}) {
51
51
  let /** @type {boolean} */
52
52
  _initialized = false,
53
53
  /** @type {boolean} */
54
- _paused = true,
54
+ _paused,
55
55
  /** @type {HTMLCanvasElement} _canvas */
56
56
  _canvas,
57
57
  /** @type {number} */
@@ -68,8 +68,8 @@ export default function litecanvas(settings = {}) {
68
68
  _fpsInterval = 1000 / 60,
69
69
  /** @type {number} */
70
70
  _accumulated,
71
- /** @type {number?} */
72
- _rafid,
71
+ /** @type {number} */
72
+ _rafid = 0,
73
73
  /** @type {number} */
74
74
  _defaultTextColor = 3,
75
75
  /** @type {string} */
@@ -86,9 +86,6 @@ export default function litecanvas(settings = {}) {
86
86
  _colorPaletteState = [],
87
87
  /** @type {number[]} */
88
88
  _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1],
89
- /** @type {string} list of functions copied from `Math` module */
90
- _mathFunctions =
91
- 'PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp',
92
89
  /**
93
90
  * @type {Object<string,Set<Function>>} game event listeners
94
91
  */
@@ -1343,7 +1340,7 @@ export default function litecanvas(settings = {}) {
1343
1340
  pause() {
1344
1341
  if (!_paused) {
1345
1342
  _paused = true
1346
- cancelAnimationFrame(_rafid)
1343
+ _rafid = ~~cancelAnimationFrame(_rafid)
1347
1344
  instance.emit('paused')
1348
1345
  }
1349
1346
  },
@@ -1358,10 +1355,8 @@ export default function litecanvas(settings = {}) {
1358
1355
  'resume() cannot be called before the "init" event and neither after the quit() function'
1359
1356
  )
1360
1357
  if (_initialized && _paused) {
1358
+ startGameLoop()
1361
1359
  _paused = false
1362
- _accumulated = _fpsInterval
1363
- _lastFrameTime = perf.now()
1364
- _rafid = raf(drawFrame)
1365
1360
  instance.emit('resumed')
1366
1361
  }
1367
1362
  },
@@ -1409,11 +1404,20 @@ export default function litecanvas(settings = {}) {
1409
1404
  }
1410
1405
 
1411
1406
  // prettier-ignore
1412
- for (const k of _mathFunctions.split(',')) {
1407
+ const mathProps = 'PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp'
1408
+ for (const k of mathProps.split(',')) {
1413
1409
  // import native Math functions
1414
1410
  instance[k] = math[k]
1415
1411
  }
1416
1412
 
1413
+ function startGameLoop() {
1414
+ if (!_rafid) {
1415
+ _accumulated = 0
1416
+ _lastFrameTime = perf.now()
1417
+ _rafid = raf(drawFrame)
1418
+ }
1419
+ }
1420
+
1417
1421
  function init() {
1418
1422
  // listen window resize event when "autoscale" is enabled
1419
1423
  if (settings.autoscale) {
@@ -1600,6 +1604,7 @@ export default function litecanvas(settings = {}) {
1600
1604
  })
1601
1605
  }
1602
1606
 
1607
+ // default keyboard handler
1603
1608
  if (settings.keyboardEvents) {
1604
1609
  /** @type {Set<string>} */
1605
1610
  const _keysDown = new Set()
@@ -1677,8 +1682,10 @@ export default function litecanvas(settings = {}) {
1677
1682
 
1678
1683
  // start the engine
1679
1684
  _initialized = true
1680
- instance.resume()
1681
1685
  instance.emit('init', instance)
1686
+ if (!_paused) {
1687
+ startGameLoop()
1688
+ }
1682
1689
  }
1683
1690
 
1684
1691
  function drawFrame() {
@@ -1703,22 +1710,24 @@ export default function litecanvas(settings = {}) {
1703
1710
  }
1704
1711
 
1705
1712
  if (updated) {
1713
+ // draws only when an update happens.
1706
1714
  instance.emit('draw', _ctx)
1715
+
1716
+ // sometimes the FPS locks at a value below 60
1717
+ // and does not go back up, even with a very simple logic.
1718
+ // One solution I found was to reset the variable that
1719
+ // accumulates time between frames, when multiple updates occur.
1707
1720
  if (updated > 1) {
1708
1721
  _accumulated = 0
1709
- DEV: console.warn(
1710
- loggerPrefix +
1711
- 'the last frame updated ' +
1712
- updated +
1713
- ' times. This can drop the FPS if it keeps happening.'
1714
- )
1715
1722
  }
1716
1723
  }
1717
1724
  }
1718
1725
 
1719
1726
  function setupCanvas() {
1727
+ const d = document
1728
+
1720
1729
  if ('string' === typeof settings.canvas) {
1721
- _canvas = document.querySelector(settings.canvas)
1730
+ _canvas = d.querySelector(settings.canvas)
1722
1731
  DEV: assert(
1723
1732
  null != _canvas,
1724
1733
  loggerPrefix + 'litecanvas() option "canvas" is an invalid CSS selector'
@@ -1727,7 +1736,7 @@ export default function litecanvas(settings = {}) {
1727
1736
  _canvas = settings.canvas
1728
1737
  }
1729
1738
 
1730
- _canvas = _canvas || document.createElement('canvas')
1739
+ _canvas = _canvas || d.createElement('canvas')
1731
1740
 
1732
1741
  DEV: assert(
1733
1742
  _canvas instanceof HTMLElement && 'CANVAS' === _canvas.tagName,
@@ -1742,7 +1751,7 @@ export default function litecanvas(settings = {}) {
1742
1751
  resizeCanvas()
1743
1752
 
1744
1753
  if (!_canvas.parentNode) {
1745
- document.body.appendChild(_canvas)
1754
+ d.body.appendChild(_canvas)
1746
1755
  }
1747
1756
 
1748
1757
  _canvas.style.imageRendering = 'pixelated'
@@ -1863,7 +1872,7 @@ export default function litecanvas(settings = {}) {
1863
1872
  }
1864
1873
 
1865
1874
  // init the engine (async)
1866
- _rafid = raf(init)
1875
+ raf(init)
1867
1876
 
1868
1877
  return instance
1869
1878
  }
package/src/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '0.205.0'
2
+ export const version = '0.206.0'