litecanvas 0.94.0 → 0.95.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
@@ -32,18 +32,18 @@
32
32
  };
33
33
 
34
34
  // src/version.js
35
- var version = "0.94.0";
35
+ var version = "0.95.0";
36
36
 
37
37
  // src/index.js
38
38
  function litecanvas(settings = {}) {
39
39
  const root = window, math = Math, TWO_PI = math.PI * 2, raf = requestAnimationFrame, _browserEventListeners = [], on = (elem, evt, callback) => {
40
40
  elem.addEventListener(evt, callback, false);
41
41
  _browserEventListeners.push(() => elem.removeEventListener(evt, callback, false));
42
- }, beginPath = (c) => c.beginPath(), isNumber = Number.isFinite, zzfx = setupZzFX(root), defaults = {
42
+ }, preventDefault = (ev) => ev.preventDefault(), beginPath = (c) => c.beginPath(), isNumber = Number.isFinite, zzfx = setupZzFX(root), defaults = {
43
43
  width: null,
44
44
  height: null,
45
45
  autoscale: true,
46
- pixelart: false,
46
+ pixelart: true,
47
47
  canvas: null,
48
48
  global: true,
49
49
  loop: null,
@@ -52,7 +52,7 @@
52
52
  animate: true
53
53
  };
54
54
  settings = Object.assign(defaults, settings);
55
- let _initialized = false, _plugins = [], _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _deltaTime = 1 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _rngSeed = Date.now(), _colors = defaultPalette, _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1], _coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized", _mathFunctions = "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp", _eventListeners = {};
55
+ let _initialized = false, _plugins = [], _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _rngSeed = Date.now(), _colors = defaultPalette, _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1], _coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized", _mathFunctions = "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp", _eventListeners = {};
56
56
  const instance = {
57
57
  /** @type {number} */
58
58
  W: 0,
@@ -958,7 +958,7 @@
958
958
  isNumber(value) && value >= 1,
959
959
  "[litecanvas] framerate() 1st param must be a positive number"
960
960
  );
961
- _deltaTime = 1 / ~~value;
961
+ _fpsInterval = 1e3 / ~~value;
962
962
  },
963
963
  /**
964
964
  * Returns information about that engine instance.
@@ -974,7 +974,7 @@
974
974
  // 1
975
975
  _initialized,
976
976
  // 2
977
- _deltaTime,
977
+ _fpsInterval / 1e3,
978
978
  // 3
979
979
  _scale,
980
980
  // 4
@@ -1028,8 +1028,8 @@
1028
1028
  */
1029
1029
  resume() {
1030
1030
  if (_initialized && !_rafid) {
1031
- _accumulated = _deltaTime;
1032
- _lastFrameTime = performance.now();
1031
+ _accumulated = _fpsInterval;
1032
+ _lastFrameTime = Date.now();
1033
1033
  _rafid = raf(drawFrame);
1034
1034
  }
1035
1035
  },
@@ -1085,7 +1085,7 @@
1085
1085
  // initial y
1086
1086
  yi: y,
1087
1087
  // timestamp
1088
- t: performance.now()
1088
+ t: Date.now()
1089
1089
  };
1090
1090
  _taps.set(id, tap);
1091
1091
  return tap;
@@ -1105,12 +1105,7 @@
1105
1105
  /**
1106
1106
  * @param {{t: number}} tap
1107
1107
  */
1108
- (tap) => tap && performance.now() - tap.t <= 300
1109
- ), preventDefault = (
1110
- /**
1111
- * @param {Event} ev
1112
- */
1113
- (ev) => ev.preventDefault()
1108
+ (tap) => tap && Date.now() - tap.t <= 300
1114
1109
  );
1115
1110
  let _pressingMouse = false;
1116
1111
  on(
@@ -1231,11 +1226,13 @@
1231
1226
  key = key.toLowerCase();
1232
1227
  return !key ? keySet.size > 0 : keySet.has("space" === key ? " " : key);
1233
1228
  };
1229
+ let _lastKey = "";
1234
1230
  on(root, "keydown", (event) => {
1235
1231
  const key = event.key.toLowerCase();
1236
1232
  if (!_keysDown.has(key)) {
1237
1233
  _keysDown.add(key);
1238
1234
  _keysPress.add(key);
1235
+ _lastKey = key === " " ? "space" : key;
1239
1236
  }
1240
1237
  });
1241
1238
  on(root, "keyup", (event) => {
@@ -1246,9 +1243,6 @@
1246
1243
  instance.def(
1247
1244
  "iskeydown",
1248
1245
  /**
1249
- * Checks if a which key is pressed (down) on the keyboard.
1250
- * Note: use `iskeydown()` to check for any key.
1251
- *
1252
1246
  * @param {string} [key]
1253
1247
  * @returns {boolean}
1254
1248
  */
@@ -1263,9 +1257,6 @@
1263
1257
  instance.def(
1264
1258
  "iskeypressed",
1265
1259
  /**
1266
- * Checks if a which key just got pressed on the keyboard.
1267
- * Note: use `iskeypressed()` to check for any key.
1268
- *
1269
1260
  * @param {string} [key]
1270
1261
  * @returns {boolean}
1271
1262
  */
@@ -1277,38 +1268,44 @@
1277
1268
  return keyCheck(_keysPress, key);
1278
1269
  }
1279
1270
  );
1271
+ instance.def(
1272
+ "lastkey",
1273
+ /**
1274
+ * @returns {string}
1275
+ */
1276
+ () => _lastKey
1277
+ );
1280
1278
  }
1281
- setInterval(() => {
1282
- if (_rafid) {
1283
- instance.pause();
1284
- instance.resume();
1285
- }
1286
- }, 5e3);
1287
1279
  _initialized = true;
1288
1280
  instance.emit("init", instance);
1289
1281
  instance.resume();
1290
1282
  }
1291
- function drawFrame(now) {
1283
+ function drawFrame() {
1292
1284
  if (!settings.animate) {
1293
1285
  return instance.emit("draw", _ctx);
1294
- } else if (_rafid) {
1295
- _rafid = raf(drawFrame);
1296
1286
  }
1287
+ let now = Date.now();
1297
1288
  let updated = 0;
1298
- let frameTime = (now - _lastFrameTime) / 1e3;
1289
+ let frameTime = now - _lastFrameTime;
1299
1290
  _lastFrameTime = now;
1300
- if (frameTime < 0.1) {
1301
- _accumulated += frameTime;
1302
- while (_accumulated >= _deltaTime) {
1303
- updated++;
1304
- instance.emit("update", _deltaTime * _timeScale, updated);
1305
- instance.def("T", instance.T + _deltaTime * _timeScale);
1306
- _accumulated -= _deltaTime;
1307
- }
1291
+ _accumulated += frameTime < 100 ? frameTime : _fpsInterval;
1292
+ while (_accumulated >= _fpsInterval) {
1293
+ updated++;
1294
+ _accumulated -= _fpsInterval;
1295
+ let dt = _fpsInterval / 1e3 * _timeScale;
1296
+ instance.emit("update", dt, updated);
1297
+ instance.def("T", instance.T + dt);
1308
1298
  }
1309
1299
  if (updated) {
1310
1300
  instance.emit("draw", _ctx);
1301
+ if (updated > 1) {
1302
+ _accumulated = 0;
1303
+ DEV: console.warn(
1304
+ "[litecanvas] the last frame updated " + updated + " times. This can drop the FPS if it keeps happening."
1305
+ );
1306
+ }
1311
1307
  }
1308
+ _rafid = raf(drawFrame);
1312
1309
  }
1313
1310
  function setupCanvas() {
1314
1311
  if ("string" === typeof settings.canvas) {
package/dist/dist.js CHANGED
@@ -31,11 +31,11 @@
31
31
  const root = window, math = Math, TWO_PI = math.PI * 2, raf = requestAnimationFrame, _browserEventListeners = [], on = (elem, evt, callback) => {
32
32
  elem.addEventListener(evt, callback, false);
33
33
  _browserEventListeners.push(() => elem.removeEventListener(evt, callback, false));
34
- }, beginPath = (c) => c.beginPath(), isNumber = Number.isFinite, zzfx = setupZzFX(root), defaults = {
34
+ }, preventDefault = (ev) => ev.preventDefault(), beginPath = (c) => c.beginPath(), isNumber = Number.isFinite, zzfx = setupZzFX(root), defaults = {
35
35
  width: null,
36
36
  height: null,
37
37
  autoscale: true,
38
- pixelart: false,
38
+ pixelart: true,
39
39
  canvas: null,
40
40
  global: true,
41
41
  loop: null,
@@ -44,7 +44,7 @@
44
44
  animate: true
45
45
  };
46
46
  settings = Object.assign(defaults, settings);
47
- let _initialized = false, _plugins = [], _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _deltaTime = 1 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _rngSeed = Date.now(), _colors = defaultPalette, _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1], _coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized", _mathFunctions = "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp", _eventListeners = {};
47
+ let _initialized = false, _plugins = [], _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _rngSeed = Date.now(), _colors = defaultPalette, _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1], _coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized", _mathFunctions = "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp", _eventListeners = {};
48
48
  const instance = {
49
49
  /** @type {number} */
50
50
  W: 0,
@@ -663,7 +663,7 @@
663
663
  * @param {number} value
664
664
  */
665
665
  framerate(value) {
666
- _deltaTime = 1 / ~~value;
666
+ _fpsInterval = 1e3 / ~~value;
667
667
  },
668
668
  /**
669
669
  * Returns information about that engine instance.
@@ -678,7 +678,7 @@
678
678
  // 1
679
679
  _initialized,
680
680
  // 2
681
- _deltaTime,
681
+ _fpsInterval / 1e3,
682
682
  // 3
683
683
  _scale,
684
684
  // 4
@@ -732,8 +732,8 @@
732
732
  */
733
733
  resume() {
734
734
  if (_initialized && !_rafid) {
735
- _accumulated = _deltaTime;
736
- _lastFrameTime = performance.now();
735
+ _accumulated = _fpsInterval;
736
+ _lastFrameTime = Date.now();
737
737
  _rafid = raf(drawFrame);
738
738
  }
739
739
  },
@@ -786,7 +786,7 @@
786
786
  // initial y
787
787
  yi: y,
788
788
  // timestamp
789
- t: performance.now()
789
+ t: Date.now()
790
790
  };
791
791
  _taps.set(id, tap);
792
792
  return tap;
@@ -806,12 +806,7 @@
806
806
  /**
807
807
  * @param {{t: number}} tap
808
808
  */
809
- (tap) => tap && performance.now() - tap.t <= 300
810
- ), preventDefault = (
811
- /**
812
- * @param {Event} ev
813
- */
814
- (ev) => ev.preventDefault()
809
+ (tap) => tap && Date.now() - tap.t <= 300
815
810
  );
816
811
  let _pressingMouse = false;
817
812
  on(
@@ -932,11 +927,13 @@
932
927
  key = key.toLowerCase();
933
928
  return !key ? keySet.size > 0 : keySet.has("space" === key ? " " : key);
934
929
  };
930
+ let _lastKey = "";
935
931
  on(root, "keydown", (event) => {
936
932
  const key = event.key.toLowerCase();
937
933
  if (!_keysDown.has(key)) {
938
934
  _keysDown.add(key);
939
935
  _keysPress.add(key);
936
+ _lastKey = key === " " ? "space" : key;
940
937
  }
941
938
  });
942
939
  on(root, "keyup", (event) => {
@@ -947,9 +944,6 @@
947
944
  instance.def(
948
945
  "iskeydown",
949
946
  /**
950
- * Checks if a which key is pressed (down) on the keyboard.
951
- * Note: use `iskeydown()` to check for any key.
952
- *
953
947
  * @param {string} [key]
954
948
  * @returns {boolean}
955
949
  */
@@ -960,9 +954,6 @@
960
954
  instance.def(
961
955
  "iskeypressed",
962
956
  /**
963
- * Checks if a which key just got pressed on the keyboard.
964
- * Note: use `iskeypressed()` to check for any key.
965
- *
966
957
  * @param {string} [key]
967
958
  * @returns {boolean}
968
959
  */
@@ -970,38 +961,41 @@
970
961
  return keyCheck(_keysPress, key);
971
962
  }
972
963
  );
964
+ instance.def(
965
+ "lastkey",
966
+ /**
967
+ * @returns {string}
968
+ */
969
+ () => _lastKey
970
+ );
973
971
  }
974
- setInterval(() => {
975
- if (_rafid) {
976
- instance.pause();
977
- instance.resume();
978
- }
979
- }, 5e3);
980
972
  _initialized = true;
981
973
  instance.emit("init", instance);
982
974
  instance.resume();
983
975
  }
984
- function drawFrame(now) {
976
+ function drawFrame() {
985
977
  if (!settings.animate) {
986
978
  return instance.emit("draw", _ctx);
987
- } else if (_rafid) {
988
- _rafid = raf(drawFrame);
989
979
  }
980
+ let now = Date.now();
990
981
  let updated = 0;
991
- let frameTime = (now - _lastFrameTime) / 1e3;
982
+ let frameTime = now - _lastFrameTime;
992
983
  _lastFrameTime = now;
993
- if (frameTime < 0.1) {
994
- _accumulated += frameTime;
995
- while (_accumulated >= _deltaTime) {
996
- updated++;
997
- instance.emit("update", _deltaTime * _timeScale, updated);
998
- instance.def("T", instance.T + _deltaTime * _timeScale);
999
- _accumulated -= _deltaTime;
1000
- }
984
+ _accumulated += frameTime < 100 ? frameTime : _fpsInterval;
985
+ while (_accumulated >= _fpsInterval) {
986
+ updated++;
987
+ _accumulated -= _fpsInterval;
988
+ let dt = _fpsInterval / 1e3 * _timeScale;
989
+ instance.emit("update", dt, updated);
990
+ instance.def("T", instance.T + dt);
1001
991
  }
1002
992
  if (updated) {
1003
993
  instance.emit("draw", _ctx);
994
+ if (updated > 1) {
995
+ _accumulated = 0;
996
+ }
1004
997
  }
998
+ _rafid = raf(drawFrame);
1005
999
  }
1006
1000
  function setupCanvas() {
1007
1001
  if ("string" === typeof settings.canvas) {
package/dist/dist.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(t={}){let a=window,i=Math,l=2*i.PI,n=requestAnimationFrame,o=[],r=(e,t,a)=>{e.addEventListener(t,a,!1),o.push(()=>e.removeEventListener(t,a,!1))},s=e=>e.beginPath(),f=(e=>{let t=new AudioContext;return e.zzfxV=1,(a=1,i=.05,l=220,n=0,o=0,r=.1,s=0,f=1,c=0,d=0,u=0,p=0,m=0,h=0,g=0,w=0,v=0,x=1,y=0,b=0,k=0)=>{let E=Math,z=2*E.PI,I=c*=500*z/44100/44100,T=l*=(1-i+2*i*E.random(i=[]))*z/44100,C=0,A=0,L=0,S=1,M=0,N=0,P=0,D=k<0?-1:1,F=z*D*k*2/44100,q=E.cos(F),B=E.sin,H=B(F)/4,O=1+H,V=-2*q/O,W=(1-H)/O,R=(1+D*q)/2/O,G=-(D+q)/O,X=0,Y=0,$=0,j=0;for(n=44100*n+9,y*=44100,o*=44100,r*=44100,v*=44100,d*=500*z/85766121e6,g*=z/44100,u*=z/44100,p*=44100,m=44100*m|0,a*=.3*e.zzfxV,D=n+y+o+r+v|0;L<D;i[L++]=P*a)++N%(100*w|0)||(P=s?1<s?2<s?3<s?B(C*C):E.max(E.min(E.tan(C),1),-1):1-(2*C/z%2+2)%2:1-4*E.abs(E.round(C/z)-C/z):B(C),P=(m?1-b+b*B(z*L/m):1)*(P<0?-1:1)*E.abs(P)**f*(L<n?L/n:L<n+y?1-(L-n)/y*(1-x):L<n+y+o?x:L<D-v?(D-L-v)/r*x:0),P=v?P/2+(v>L?0:(L<D-v?1:(D-L)/v)*i[L-v|0]/2/a):P,k&&(P=j=R*X+G*(X=Y)+R*(Y=P)-W*$-V*($=j))),C+=(F=(l+=c+=d)*E.cos(g*A++))+F*h*B(L**5),S&&++S>p&&(l+=u,T+=u,S=0),!m||++M%m||(l=T,c=I,S=S||1);(a=t.createBuffer(1,D,44100)).getChannelData(0).set(i),(l=t.createBufferSource()).buffer=a,l.connect(t.destination),l.start()}})(a);t=Object.assign({width:null,height:null,autoscale:!0,pixelart:!1,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0,animate:!0},t);let c=!1,d=[],u,p=1,m,h=.5,g=1,w,v=1/60,x,y,b="sans-serif",k=20,E=Date.now(),z=e,I=[.5,0,1750,,,.3,1,,,,600,.1],T={},C={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:l,HALF_PI:l/4,lerp:(e,t,a)=>a*(t-e)+e,deg2rad:e=>i.PI/180*e,rad2deg:e=>180/i.PI*e,round:(e,t=0)=>{if(!t)return i.round(e);let a=10**t;return i.round(e*a)/a},clamp:(e,t,a)=>e<t?t:e>a?a:e,wrap:(e,t,a)=>e-(a-t)*i.floor((e-t)/(a-t)),map(e,t,a,i,l,n){let o=(e-t)/(a-t)*(l-i)+i;return n?C.clamp(o,i,l):o},norm:(e,t,a)=>C.map(e,t,a,0,1),wave:(e,t,a,i=Math.sin)=>e+(i(a)+1)/2*(t-e),rand:(e=0,t=1)=>(E=(1664525*E+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>i.floor(C.rand(e,t+1)),rseed(e){E=~~e},cls(e){null==e?m.clearRect(0,0,m.canvas.width,m.canvas.height):C.rectfill(0,0,m.canvas.width,m.canvas.height,e)},rect(e,t,a,i,l,n){s(m),m[n?"roundRect":"rect"](~~e-h,~~t-h,~~a+2*h,~~i+2*h,n),C.stroke(l)},rectfill(e,t,a,i,l,n){s(m),m[n?"roundRect":"rect"](~~e,~~t,~~a,~~i,n),C.fill(l)},circ(e,t,a,i){s(m),m.arc(~~e,~~t,~~a,0,l),C.stroke(i)},circfill(e,t,a,i){s(m),m.arc(~~e,~~t,~~a,0,l),C.fill(i)},oval(e,t,a,i,n){s(m),m.ellipse(~~e,~~t,~~a,~~i,0,0,l),C.stroke(n)},ovalfill(e,t,a,i,n){s(m),m.ellipse(~~e,~~t,~~a,~~i,0,0,l),C.fill(n)},line(e,t,a,i,l){s(m);let n=.5*(0!==h&&~~e==~~a),o=.5*(0!==h&&~~t==~~i);m.moveTo(~~e+n,~~t+o),m.lineTo(~~a+n,~~i+o),C.stroke(l)},linewidth(e){m.lineWidth=~~e,h=.5*(0!=~~e%2)},linedash(e,t=0){m.setLineDash(e),m.lineDashOffset=t},text(e,t,a,i=3,l="normal"){m.font=`${l} ${k}px ${b}`,m.fillStyle=z[~~i%z.length],m.fillText(a,~~e,~~t)},textfont(e){b=e},textsize(e){k=e},textalign(e,t){e&&(m.textAlign=e),t&&(m.textBaseline=t)},image(e,t,a){m.drawImage(a,~~e,~~t)},paint(e,t,a,i={}){let l=i.canvas||new OffscreenCanvas(1,1),n=i.scale||1,o=m;if(l.width=e*n,l.height=t*n,(m=l.getContext("2d")).scale(n,n),Array.isArray(a)){let e=0,t=0;for(let i of(m.imageSmoothingEnabled=!1,a)){for(let a of i)" "!==a&&"."!==a&&C.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(m);return m=o,l.transferToImageBitmap()},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),alpha(e){m.globalAlpha=C.clamp(e,0,1)},fill(e){m.fillStyle=z[~~e%z.length],m.fill()},stroke(e){m.strokeStyle=z[~~e%z.length],m.stroke()},clip(e){s(m),e(m),m.clip()},sfx:(e,t=0,i=1)=>!!a.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||I,(0!==t||1!==i)&&((e=e.slice())[0]=i*(e[0]||1),e[10]=~~e[10]+t),f.apply(0,e),e),volume(e){a.zzfxV=e},canvas:()=>u,use(e,t={}){c?N(e,t):d.push([e,t])},listen:(e,t)=>(T[e=e.toLowerCase()]=T[e]||new Set,T[e].add(t),()=>T&&T[e].delete(t)),emit(e,t,a,i,l){c&&(M("before:"+(e=e.toLowerCase()),t,a,i,l),M(e,t,a,i,l),M("after:"+e,t,a,i,l))},pal(t=e){z=t},def(e,i){C[e]=i,t.global&&(a[e]=i)},timescale(e){g=e},framerate(e){v=1/~~e},stat(e){let i={index:e,value:[t,c,v,p,T,z,I,g,a.zzfxV,E,k,b][e]};return C.emit("stat",i),i.value},quit(){for(let e of(C.pause(),C.emit("quit"),T={},o))e();if(t.global){for(let e in C)delete a[e];delete a.ENGINE}c=!1},pause(){cancelAnimationFrame(y),y=0},resume(){c&&!y&&(x=v,w=performance.now(),y=n(L))},paused:()=>!y};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))C[e]=i[e];function A(){let e=t.loop?t.loop:a;for(let t of"init,update,draw,tap,untap,tapping,tapped,resized".split(","))e[t]&&C.listen(t,e[t]);for(let[e,t]of d)N(e,t);if(t.autoscale&&r(a,"resize",S),t.tapEvents){let e=e=>[(e.pageX-u.offsetLeft)/p,(e.pageY-u.offsetTop)/p],t=new Map,i=(e,a,i)=>{let l={x:a,y:i,xi:a,yi:i,t:performance.now()};return t.set(e,l),l},l=(e,a,l)=>{let n=t.get(e)||i(e);n.x=a,n.y=l},n=e=>e&&performance.now()-e.t<=300,o=e=>e.preventDefault(),s=!1;r(u,"mousedown",t=>{if(0===t.button){o(t);let[a,l]=e(t);C.emit("tap",a,l,0),i(0,a,l),s=!0}}),r(u,"mouseup",a=>{if(0===a.button){o(a);let i=t.get(0),[l,r]=e(a);n(i)&&C.emit("tapped",i.xi,i.yi,0),C.emit("untap",l,r,0),t.delete(0),s=!1}}),r(a,"mousemove",t=>{o(t);let[a,i]=e(t);C.def("MX",a),C.def("MY",i),s&&(C.emit("tapping",a,i,0),l(0,a,i))}),r(u,"touchstart",t=>{for(let a of(o(t),t.changedTouches)){let[t,l]=e(a);C.emit("tap",t,l,a.identifier+1),i(a.identifier+1,t,l)}}),r(u,"touchmove",t=>{for(let a of(o(t),t.changedTouches)){let[t,i]=e(a);C.emit("tapping",t,i,a.identifier+1),l(a.identifier+1,t,i)}});let f=e=>{o(e);let a=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,i]of t)a.includes(e)||(n(i)&&C.emit("tapped",i.xi,i.yi,e),C.emit("untap",i.x,i.y,e),t.delete(e))};r(u,"touchend",f),r(u,"touchcancel",f),r(a,"blur",()=>{for(let[e,a]of(s=!1,t))C.emit("untap",a.x,a.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,i=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0;r(a,"keydown",a=>{let i=a.key.toLowerCase();e.has(i)||(e.add(i),t.add(i))}),r(a,"keyup",t=>{e.delete(t.key.toLowerCase())}),r(a,"blur",()=>e.clear()),C.listen("after:update",()=>t.clear()),C.def("iskeydown",t=>i(e,t)),C.def("iskeypressed",e=>i(t,e))}setInterval(()=>{y&&(C.pause(),C.resume())},5e3),c=!0,C.emit("init",C),C.resume()}function L(e){if(!t.animate)return C.emit("draw",m);y&&(y=n(L));let a=0,i=(e-w)/1e3;if(w=e,i<.1)for(x+=i;x>=v;)a++,C.emit("update",v*g,a),C.def("T",C.T+v*g),x-=v;a&&C.emit("draw",m)}function S(){let e=t.width>0?t.width:innerWidth,a=t.width>0?t.height||t.width:innerHeight;if(C.def("W",e),C.def("H",a),u.width=e,u.height=a,t.autoscale){let l=+t.autoscale;u.style.display||(u.style.display="block",u.style.margin="auto"),p=i.min(innerWidth/e,innerHeight/a),p=l>1&&p>l?l:p,u.style.width=e*p+"px",u.style.height=a*p+"px"}t.pixelart&&(m.imageSmoothingEnabled=!1,u.style.imageRendering="pixelated"),C.textalign("start","top"),C.emit("resized",p),t.animate||n(L)}function M(e,t,a,i,l){if(T[e])for(let n of T[e])n(t,a,i,l)}function N(e,t){let a=e(C,t);for(let e in a)C.def(e,a[e])}if(t.global){if(a.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(a,C),a.ENGINE=C}return m=(u=(u="string"==typeof t.canvas?document.querySelector(t.canvas):t.canvas)||document.createElement("canvas")).getContext("2d"),r(u,"click",()=>focus()),u.style="",S(),u.parentNode||document.body.appendChild(u),u.oncontextmenu=()=>!1,"loading"===document.readyState?r(a,"DOMContentLoaded",()=>n(A)):n(A),C}})();
1
+ (()=>{var e=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(t={}){let a=window,i=Math,l=2*i.PI,n=requestAnimationFrame,o=[],r=(e,t,a)=>{e.addEventListener(t,a,!1),o.push(()=>e.removeEventListener(t,a,!1))},s=e=>e.preventDefault(),f=e=>e.beginPath(),c=(e=>{let t=new AudioContext;return e.zzfxV=1,(a=1,i=.05,l=220,n=0,o=0,r=.1,s=0,f=1,c=0,d=0,u=0,p=0,h=0,m=0,g=0,w=0,v=0,x=1,y=0,b=0,k=0)=>{let E=Math,z=2*E.PI,T=c*=500*z/44100/44100,C=l*=(1-i+2*i*E.random(i=[]))*z/44100,I=0,A=0,L=0,S=1,D=0,M=0,N=0,P=k<0?-1:1,F=z*P*k*2/44100,q=E.cos(F),B=E.sin,H=B(F)/4,O=1+H,V=-2*q/O,W=(1-H)/O,R=(1+P*q)/2/O,G=-(P+q)/O,X=0,Y=0,$=0,j=0;for(n=44100*n+9,y*=44100,o*=44100,r*=44100,v*=44100,d*=500*z/85766121e6,g*=z/44100,u*=z/44100,p*=44100,h=44100*h|0,a*=.3*e.zzfxV,P=n+y+o+r+v|0;L<P;i[L++]=N*a)++M%(100*w|0)||(N=s?1<s?2<s?3<s?B(I*I):E.max(E.min(E.tan(I),1),-1):1-(2*I/z%2+2)%2:1-4*E.abs(E.round(I/z)-I/z):B(I),N=(h?1-b+b*B(z*L/h):1)*(N<0?-1:1)*E.abs(N)**f*(L<n?L/n:L<n+y?1-(L-n)/y*(1-x):L<n+y+o?x:L<P-v?(P-L-v)/r*x:0),N=v?N/2+(v>L?0:(L<P-v?1:(P-L)/v)*i[L-v|0]/2/a):N,k&&(N=j=R*X+G*(X=Y)+R*(Y=N)-W*$-V*($=j))),I+=(F=(l+=c+=d)*E.cos(g*A++))+F*m*B(L**5),S&&++S>p&&(l+=u,C+=u,S=0),!h||++D%h||(l=C,c=T,S=S||1);(a=t.createBuffer(1,P,44100)).getChannelData(0).set(i),(l=t.createBufferSource()).buffer=a,l.connect(t.destination),l.start()}})(a);t=Object.assign({width:null,height:null,autoscale:!0,pixelart:!0,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0,animate:!0},t);let d=!1,u=[],p,h=1,m,g=.5,w=1,v,x=1e3/60,y,b,k="sans-serif",E=20,z=Date.now(),T=e,C=[.5,0,1750,,,.3,1,,,,600,.1],I={},A={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:l,HALF_PI:l/4,lerp:(e,t,a)=>a*(t-e)+e,deg2rad:e=>i.PI/180*e,rad2deg:e=>180/i.PI*e,round:(e,t=0)=>{if(!t)return i.round(e);let a=10**t;return i.round(e*a)/a},clamp:(e,t,a)=>e<t?t:e>a?a:e,wrap:(e,t,a)=>e-(a-t)*i.floor((e-t)/(a-t)),map(e,t,a,i,l,n){let o=(e-t)/(a-t)*(l-i)+i;return n?A.clamp(o,i,l):o},norm:(e,t,a)=>A.map(e,t,a,0,1),wave:(e,t,a,i=Math.sin)=>e+(i(a)+1)/2*(t-e),rand:(e=0,t=1)=>(z=(1664525*z+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>i.floor(A.rand(e,t+1)),rseed(e){z=~~e},cls(e){null==e?m.clearRect(0,0,m.canvas.width,m.canvas.height):A.rectfill(0,0,m.canvas.width,m.canvas.height,e)},rect(e,t,a,i,l,n){f(m),m[n?"roundRect":"rect"](~~e-g,~~t-g,~~a+2*g,~~i+2*g,n),A.stroke(l)},rectfill(e,t,a,i,l,n){f(m),m[n?"roundRect":"rect"](~~e,~~t,~~a,~~i,n),A.fill(l)},circ(e,t,a,i){f(m),m.arc(~~e,~~t,~~a,0,l),A.stroke(i)},circfill(e,t,a,i){f(m),m.arc(~~e,~~t,~~a,0,l),A.fill(i)},oval(e,t,a,i,n){f(m),m.ellipse(~~e,~~t,~~a,~~i,0,0,l),A.stroke(n)},ovalfill(e,t,a,i,n){f(m),m.ellipse(~~e,~~t,~~a,~~i,0,0,l),A.fill(n)},line(e,t,a,i,l){f(m);let n=.5*(0!==g&&~~e==~~a),o=.5*(0!==g&&~~t==~~i);m.moveTo(~~e+n,~~t+o),m.lineTo(~~a+n,~~i+o),A.stroke(l)},linewidth(e){m.lineWidth=~~e,g=.5*(0!=~~e%2)},linedash(e,t=0){m.setLineDash(e),m.lineDashOffset=t},text(e,t,a,i=3,l="normal"){m.font=`${l} ${E}px ${k}`,m.fillStyle=T[~~i%T.length],m.fillText(a,~~e,~~t)},textfont(e){k=e},textsize(e){E=e},textalign(e,t){e&&(m.textAlign=e),t&&(m.textBaseline=t)},image(e,t,a){m.drawImage(a,~~e,~~t)},paint(e,t,a,i={}){let l=i.canvas||new OffscreenCanvas(1,1),n=i.scale||1,o=m;if(l.width=e*n,l.height=t*n,(m=l.getContext("2d")).scale(n,n),Array.isArray(a)){let e=0,t=0;for(let i of(m.imageSmoothingEnabled=!1,a)){for(let a of i)" "!==a&&"."!==a&&A.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(m);return m=o,l.transferToImageBitmap()},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),alpha(e){m.globalAlpha=A.clamp(e,0,1)},fill(e){m.fillStyle=T[~~e%T.length],m.fill()},stroke(e){m.strokeStyle=T[~~e%T.length],m.stroke()},clip(e){f(m),e(m),m.clip()},sfx:(e,t=0,i=1)=>!!a.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||C,(0!==t||1!==i)&&((e=e.slice())[0]=i*(e[0]||1),e[10]=~~e[10]+t),c.apply(0,e),e),volume(e){a.zzfxV=e},canvas:()=>p,use(e,t={}){d?N(e,t):u.push([e,t])},listen:(e,t)=>(I[e=e.toLowerCase()]=I[e]||new Set,I[e].add(t),()=>I&&I[e].delete(t)),emit(e,t,a,i,l){d&&(M("before:"+(e=e.toLowerCase()),t,a,i,l),M(e,t,a,i,l),M("after:"+e,t,a,i,l))},pal(t=e){T=t},def(e,i){A[e]=i,t.global&&(a[e]=i)},timescale(e){w=e},framerate(e){x=1e3/~~e},stat(e){let i={index:e,value:[t,d,x/1e3,h,I,T,C,w,a.zzfxV,z,E,k][e]};return A.emit("stat",i),i.value},quit(){for(let e of(A.pause(),A.emit("quit"),I={},o))e();if(t.global){for(let e in A)delete a[e];delete a.ENGINE}d=!1},pause(){cancelAnimationFrame(b),b=0},resume(){d&&!b&&(y=x,v=Date.now(),b=n(S))},paused:()=>!b};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))A[e]=i[e];function L(){let e=t.loop?t.loop:a;for(let t of"init,update,draw,tap,untap,tapping,tapped,resized".split(","))e[t]&&A.listen(t,e[t]);for(let[e,t]of u)N(e,t);if(t.autoscale&&r(a,"resize",D),t.tapEvents){let e=e=>[(e.pageX-p.offsetLeft)/h,(e.pageY-p.offsetTop)/h],t=new Map,i=(e,a,i)=>{let l={x:a,y:i,xi:a,yi:i,t:Date.now()};return t.set(e,l),l},l=(e,a,l)=>{let n=t.get(e)||i(e);n.x=a,n.y=l},n=e=>e&&Date.now()-e.t<=300,o=!1;r(p,"mousedown",t=>{if(0===t.button){s(t);let[a,l]=e(t);A.emit("tap",a,l,0),i(0,a,l),o=!0}}),r(p,"mouseup",a=>{if(0===a.button){s(a);let i=t.get(0),[l,r]=e(a);n(i)&&A.emit("tapped",i.xi,i.yi,0),A.emit("untap",l,r,0),t.delete(0),o=!1}}),r(a,"mousemove",t=>{s(t);let[a,i]=e(t);A.def("MX",a),A.def("MY",i),o&&(A.emit("tapping",a,i,0),l(0,a,i))}),r(p,"touchstart",t=>{for(let a of(s(t),t.changedTouches)){let[t,l]=e(a);A.emit("tap",t,l,a.identifier+1),i(a.identifier+1,t,l)}}),r(p,"touchmove",t=>{for(let a of(s(t),t.changedTouches)){let[t,i]=e(a);A.emit("tapping",t,i,a.identifier+1),l(a.identifier+1,t,i)}});let f=e=>{s(e);let a=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,i]of t)a.includes(e)||(n(i)&&A.emit("tapped",i.xi,i.yi,e),A.emit("untap",i.x,i.y,e),t.delete(e))};r(p,"touchend",f),r(p,"touchcancel",f),r(a,"blur",()=>{for(let[e,a]of(o=!1,t))A.emit("untap",a.x,a.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,i=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0,l="";r(a,"keydown",a=>{let i=a.key.toLowerCase();e.has(i)||(e.add(i),t.add(i),l=" "===i?"space":i)}),r(a,"keyup",t=>{e.delete(t.key.toLowerCase())}),r(a,"blur",()=>e.clear()),A.listen("after:update",()=>t.clear()),A.def("iskeydown",t=>i(e,t)),A.def("iskeypressed",e=>i(t,e)),A.def("lastkey",()=>l)}d=!0,A.emit("init",A),A.resume()}function S(){if(!t.animate)return A.emit("draw",m);let e=Date.now(),a=0,i=e-v;for(v=e,y+=i<100?i:x;y>=x;){a++,y-=x;let e=x/1e3*w;A.emit("update",e,a),A.def("T",A.T+e)}a&&(A.emit("draw",m),a>1&&(y=0)),b=n(S)}function D(){let e=t.width>0?t.width:innerWidth,a=t.width>0?t.height||t.width:innerHeight;if(A.def("W",e),A.def("H",a),p.width=e,p.height=a,t.autoscale){let l=+t.autoscale;p.style.display||(p.style.display="block",p.style.margin="auto"),h=i.min(innerWidth/e,innerHeight/a),h=l>1&&h>l?l:h,p.style.width=e*h+"px",p.style.height=a*h+"px"}t.pixelart&&(m.imageSmoothingEnabled=!1,p.style.imageRendering="pixelated"),A.textalign("start","top"),A.emit("resized",h),t.animate||n(S)}function M(e,t,a,i,l){if(I[e])for(let n of I[e])n(t,a,i,l)}function N(e,t){let a=e(A,t);for(let e in a)A.def(e,a[e])}if(t.global){if(a.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(a,A),a.ENGINE=A}return m=(p=(p="string"==typeof t.canvas?document.querySelector(t.canvas):t.canvas)||document.createElement("canvas")).getContext("2d"),r(p,"click",()=>focus()),p.style="",D(),p.parentNode||document.body.appendChild(p),p.oncontextmenu=()=>!1,"loading"===document.readyState?r(a,"DOMContentLoaded",()=>n(L)):n(L),A}})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.94.0",
3
+ "version": "0.95.0",
4
4
  "description": "Lightweight HTML5 canvas 2D game engine suitable for small projects and creative coding. Inspired by PICO-8 and P5/Processing.",
5
5
  "license": "MIT",
6
6
  "author": "Luiz Bills <luizbills@pm.me>",
@@ -33,7 +33,7 @@
33
33
  "devDependencies": {
34
34
  "@litecanvas/jsdom-extras": "^2.0.1",
35
35
  "@size-limit/preset-small-lib": "^11.2.0",
36
- "@swc/core": "^1.13.1",
36
+ "@swc/core": "^1.13.2",
37
37
  "@types/jsdom": "^21.1.7",
38
38
  "ava": "^6.4.1",
39
39
  "esbuild": "^0.25.8",
package/src/index.js CHANGED
@@ -23,6 +23,8 @@ export default function litecanvas(settings = {}) {
23
23
  elem.addEventListener(evt, callback, false)
24
24
  _browserEventListeners.push(() => elem.removeEventListener(evt, callback, false))
25
25
  },
26
+ /** @type {(ev: Event) => void} */
27
+ preventDefault = (ev) => ev.preventDefault(),
26
28
  /** @type {(c: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D) => void} */
27
29
  beginPath = (c) => c.beginPath(),
28
30
  isNumber = Number.isFinite,
@@ -32,7 +34,7 @@ export default function litecanvas(settings = {}) {
32
34
  width: null,
33
35
  height: null,
34
36
  autoscale: true,
35
- pixelart: false,
37
+ pixelart: true,
36
38
  canvas: null,
37
39
  global: true,
38
40
  loop: null,
@@ -61,7 +63,7 @@ export default function litecanvas(settings = {}) {
61
63
  /** @type {number} */
62
64
  _lastFrameTime,
63
65
  /** @type {number} duration of a frame at 60 FPS (default) */
64
- _deltaTime = 1 / 60,
66
+ _fpsInterval = 1000 / 60,
65
67
  /** @type {number} */
66
68
  _accumulated,
67
69
  /** @type {number?} */
@@ -1120,7 +1122,7 @@ export default function litecanvas(settings = {}) {
1120
1122
  '[litecanvas] framerate() 1st param must be a positive number'
1121
1123
  )
1122
1124
 
1123
- _deltaTime = 1 / ~~value
1125
+ _fpsInterval = 1000 / ~~value
1124
1126
  },
1125
1127
 
1126
1128
  /**
@@ -1138,7 +1140,7 @@ export default function litecanvas(settings = {}) {
1138
1140
  // 1
1139
1141
  _initialized,
1140
1142
  // 2
1141
- _deltaTime,
1143
+ _fpsInterval / 1000,
1142
1144
  // 3
1143
1145
  _scale,
1144
1146
  // 4
@@ -1210,8 +1212,8 @@ export default function litecanvas(settings = {}) {
1210
1212
  */
1211
1213
  resume() {
1212
1214
  if (_initialized && !_rafid) {
1213
- _accumulated = _deltaTime
1214
- _lastFrameTime = performance.now()
1215
+ _accumulated = _fpsInterval
1216
+ _lastFrameTime = Date.now()
1215
1217
  _rafid = raf(drawFrame)
1216
1218
  }
1217
1219
  },
@@ -1280,7 +1282,7 @@ export default function litecanvas(settings = {}) {
1280
1282
  // initial y
1281
1283
  yi: y,
1282
1284
  // timestamp
1283
- t: performance.now(),
1285
+ t: Date.now(),
1284
1286
  }
1285
1287
  _taps.set(id, tap)
1286
1288
  return tap
@@ -1300,12 +1302,7 @@ export default function litecanvas(settings = {}) {
1300
1302
  /**
1301
1303
  * @param {{t: number}} tap
1302
1304
  */
1303
- (tap) => tap && performance.now() - tap.t <= 300,
1304
- preventDefault =
1305
- /**
1306
- * @param {Event} ev
1307
- */
1308
- (ev) => ev.preventDefault()
1305
+ (tap) => tap && Date.now() - tap.t <= 300
1309
1306
 
1310
1307
  let _pressingMouse = false
1311
1308
 
@@ -1454,11 +1451,15 @@ export default function litecanvas(settings = {}) {
1454
1451
  return !key ? keySet.size > 0 : keySet.has('space' === key ? ' ' : key)
1455
1452
  }
1456
1453
 
1454
+ /** @type {string} */
1455
+ let _lastKey = ''
1456
+
1457
1457
  on(root, 'keydown', (/** @type {KeyboardEvent} */ event) => {
1458
1458
  const key = event.key.toLowerCase()
1459
1459
  if (!_keysDown.has(key)) {
1460
1460
  _keysDown.add(key)
1461
1461
  _keysPress.add(key)
1462
+ _lastKey = key === ' ' ? 'space' : key
1462
1463
  }
1463
1464
  })
1464
1465
 
@@ -1472,9 +1473,6 @@ export default function litecanvas(settings = {}) {
1472
1473
  instance.def(
1473
1474
  'iskeydown',
1474
1475
  /**
1475
- * Checks if a which key is pressed (down) on the keyboard.
1476
- * Note: use `iskeydown()` to check for any key.
1477
- *
1478
1476
  * @param {string} [key]
1479
1477
  * @returns {boolean}
1480
1478
  */
@@ -1490,9 +1488,6 @@ export default function litecanvas(settings = {}) {
1490
1488
  instance.def(
1491
1489
  'iskeypressed',
1492
1490
  /**
1493
- * Checks if a which key just got pressed on the keyboard.
1494
- * Note: use `iskeypressed()` to check for any key.
1495
- *
1496
1491
  * @param {string} [key]
1497
1492
  * @returns {boolean}
1498
1493
  */
@@ -1504,16 +1499,15 @@ export default function litecanvas(settings = {}) {
1504
1499
  return keyCheck(_keysPress, key)
1505
1500
  }
1506
1501
  )
1507
- }
1508
1502
 
1509
- // this seems to solve a wierd bug that drop the FPS
1510
- // when switching tabs in the browser
1511
- setInterval(() => {
1512
- if (_rafid) {
1513
- instance.pause()
1514
- instance.resume()
1515
- }
1516
- }, 5000)
1503
+ instance.def(
1504
+ 'lastkey',
1505
+ /**
1506
+ * @returns {string}
1507
+ */
1508
+ () => _lastKey
1509
+ )
1510
+ }
1517
1511
 
1518
1512
  // start the engine
1519
1513
  _initialized = true
@@ -1521,37 +1515,42 @@ export default function litecanvas(settings = {}) {
1521
1515
  instance.resume()
1522
1516
  }
1523
1517
 
1524
- /**
1525
- * @param {DOMHighResTimeStamp} now
1526
- */
1527
- function drawFrame(now) {
1518
+ function drawFrame() {
1528
1519
  if (!settings.animate) {
1529
1520
  return instance.emit('draw', _ctx)
1530
1521
  }
1531
- // request the next frame
1532
- // only when the engine loop are not paused (_rafid >= 1)
1533
- else if (_rafid) {
1534
- _rafid = raf(drawFrame)
1535
- }
1536
1522
 
1523
+ let now = Date.now()
1537
1524
  let updated = 0
1538
- let frameTime = (now - _lastFrameTime) / 1000
1525
+ let frameTime = now - _lastFrameTime
1539
1526
 
1540
1527
  _lastFrameTime = now
1528
+ _accumulated += frameTime < 100 ? frameTime : _fpsInterval
1541
1529
 
1542
- if (frameTime < 0.1) {
1543
- _accumulated += frameTime
1544
- while (_accumulated >= _deltaTime) {
1545
- updated++
1546
- instance.emit('update', _deltaTime * _timeScale, updated)
1547
- instance.def('T', instance.T + _deltaTime * _timeScale)
1548
- _accumulated -= _deltaTime
1549
- }
1530
+ while (_accumulated >= _fpsInterval) {
1531
+ updated++
1532
+ _accumulated -= _fpsInterval
1533
+
1534
+ let dt = (_fpsInterval / 1000) * _timeScale
1535
+
1536
+ instance.emit('update', dt, updated)
1537
+ instance.def('T', instance.T + dt)
1550
1538
  }
1551
1539
 
1552
1540
  if (updated) {
1553
1541
  instance.emit('draw', _ctx)
1542
+ if (updated > 1) {
1543
+ _accumulated = 0
1544
+ DEV: console.warn(
1545
+ '[litecanvas] the last frame updated ' +
1546
+ updated +
1547
+ ' times. This can drop the FPS if it keeps happening.'
1548
+ )
1549
+ }
1554
1550
  }
1551
+
1552
+ // request the next frame
1553
+ _rafid = raf(drawFrame)
1555
1554
  }
1556
1555
 
1557
1556
  function setupCanvas() {
package/src/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '0.94.0'
2
+ export const version = '0.95.0'
package/types/global.d.ts CHANGED
@@ -477,7 +477,7 @@ declare global {
477
477
  */
478
478
  function volume(value: number): void
479
479
 
480
- /** UTILS API */
480
+ /** KEYBOARD API */
481
481
  /**
482
482
  * Checks if a which key is pressed on the keyboard.
483
483
  * Note: use `iskeydown()` to check for any key pressed.
@@ -494,6 +494,12 @@ declare global {
494
494
  * @returns `true` if the which key was pressed
495
495
  */
496
496
  function iskeypressed(key: string): boolean
497
+ /**
498
+ * Returns the last pressed.
499
+ *
500
+ * @returns {string}
501
+ */
502
+ function lastkey(): string
497
503
 
498
504
  /** PLUGINS API */
499
505
  /**
package/types/types.d.ts CHANGED
@@ -467,7 +467,7 @@ type LitecanvasInstance = {
467
467
  */
468
468
  volume(value: number): void
469
469
 
470
- /** UTILS API */
470
+ /** KEYBOARD API */
471
471
  /**
472
472
  * Checks if a which key is pressed on the keyboard.
473
473
  * Note: use `iskeydown()` to check for any key pressed.
@@ -484,6 +484,12 @@ type LitecanvasInstance = {
484
484
  * @returns `true` if the which key was pressed
485
485
  */
486
486
  iskeypressed?(key: string): boolean
487
+ /**
488
+ * Returns the last pressed.
489
+ *
490
+ * @returns {string}
491
+ */
492
+ lastkey?(): string
487
493
 
488
494
  /** PLUGINS API */
489
495
  /**
@@ -603,7 +609,7 @@ type LitecanvasOptions = {
603
609
  * If `true`, the pixel art images won't look blurry.
604
610
  * Also, disables canvas built-in antialias.
605
611
  *
606
- * Default: `false`
612
+ * Default: `true`
607
613
  */
608
614
  pixelart?: boolean
609
615
  /**
@@ -613,16 +619,17 @@ type LitecanvasOptions = {
613
619
  /**
614
620
  * Specify your game loop callbacks.
615
621
  * By default use that global functions (if they exist):
616
- * - `window.init(): void`
622
+ * - `window.init(instance: LitecanvasInstance): void`
617
623
  * - `window.update(dt: number): void`
618
- * - `window.draw(): void`
619
- * - `window.resized(): void`
620
- * - `window.tap(tapX: number, tapY: number, tapId: number): void`
621
- * - `window.untap(tapX: number, tapY: number, tapId: number): void`
622
- * - `window.tapped(tapX: number, tapY: number, tapId: number): void`
623
- * - `window.tapping(tapX: number, tapY: number, tapId: number): void`
624
+ * - `window.draw(ctx: CanvasRenderingContext2D): void`
625
+ * - `window.resized(scale: number): void`
626
+ * - `window.tap(tapX: number, tapY: number, touchId: number): void`
627
+ * - `window.untap(tapX: number, tapY: number, touchId: number): void`
628
+ * - `window.tapped(tapX: number, tapY: number, touchId: number): void`
629
+ * - `window.tapping(tapX: number, tapY: number, touchId: number): void`
624
630
  */
625
631
  loop?: LitecanvasGameLoop
632
+
626
633
  /**
627
634
  * default: `true`
628
635
  *
@@ -652,10 +659,10 @@ type LitecanvasGameLoop = {
652
659
  update?: (dt: number) => void
653
660
  draw?: () => void
654
661
  resized?: () => void
655
- tap?: (tapX: number, tapY: number, tapId: number) => void
656
- untap?: (tapX: number, tapY: number, tapId: number) => void
657
- tapped?: (tapX: number, tapY: number, tapId: number) => void
658
- tapping?: (tapX: number, tapY: number, tapId: number) => void
662
+ tap?: (tapX: number, tapY: number, touchId: number) => void
663
+ untap?: (tapX: number, tapY: number, touchId: number) => void
664
+ tapped?: (tapX: number, tapY: number, touchId: number) => void
665
+ tapping?: (tapX: number, tapY: number, touchId: number) => void
659
666
  }
660
667
 
661
668
  type drawCallback = (context: OffscreenCanvasRenderingContext2D) => void