litecanvas 0.74.0 → 0.74.2

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
@@ -68,7 +68,7 @@
68
68
  animate: true
69
69
  };
70
70
  settings = Object.assign(defaults, settings);
71
- let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _fullscreen = settings.fullscreen, _autoscale = settings.autoscale, _animated = settings.animate, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fixedDeltaTime, _accumulated, _focused = true, _fontFamily = "sans-serif", _fontSize = 32, _rng_seed = Date.now(), _global = settings.global, _events = {
71
+ let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _fullscreen = settings.fullscreen, _autoscale = settings.autoscale, _animated = settings.animate, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _deltaTime, _accumulated = 0, _rafid, _fontFamily = "sans-serif", _fontSize = 32, _rng_seed = Date.now(), _global = settings.global, _events = {
72
72
  init: null,
73
73
  update: null,
74
74
  draw: null,
@@ -312,7 +312,7 @@
312
312
  },
313
313
  /** BASIC GRAPHICS API */
314
314
  /**
315
- * Clear the game screen
315
+ * Clear the game screen with an optional color
316
316
  *
317
317
  * @param {number?} color The background color (index) or null (for transparent)
318
318
  */
@@ -320,14 +320,19 @@
320
320
  if (true) {
321
321
  assert(
322
322
  null == color || isFinite(color) && color >= 0,
323
- "cls: 1st param must be a number"
323
+ "cls: 1st param must be a positive number or zero or null"
324
324
  );
325
325
  }
326
- let width = _ctx.canvas.width, height = _ctx.canvas.height;
327
326
  if (null == color) {
328
- _ctx.clearRect(0, 0, width, height);
327
+ _ctx.clearRect(0, 0, _ctx.canvas.width, _ctx.canvas.height);
329
328
  } else {
330
- instance.rectfill(0, 0, width, height, color);
329
+ instance.rectfill(
330
+ 0,
331
+ 0,
332
+ _ctx.canvas.width,
333
+ _ctx.canvas.height,
334
+ color
335
+ );
331
336
  }
332
337
  },
333
338
  /**
@@ -593,11 +598,20 @@
593
598
  textalign(align, baseline) {
594
599
  if (true) {
595
600
  assert(
596
- null == align || "string" === typeof align,
601
+ null == align || ["left", "right", "center", "start", "end"].includes(
602
+ align
603
+ ),
597
604
  "textalign: 1st param must be a string"
598
605
  );
599
606
  assert(
600
- null == baseline || "string" === typeof baseline,
607
+ null == baseline || [
608
+ "top",
609
+ "bottom",
610
+ "middle",
611
+ "hanging",
612
+ "alphabetic",
613
+ "ideographic"
614
+ ].includes(baseline),
601
615
  "textalign: 2nd param must be a string"
602
616
  );
603
617
  }
@@ -672,8 +686,8 @@
672
686
  /**
673
687
  * Get or set the canvas context 2D
674
688
  *
675
- * @param {CanvasRenderingContext2D} [context]
676
- * @returns {CanvasRenderingContext2D}
689
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
690
+ * @returns {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D}
677
691
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
678
692
  */
679
693
  ctx(context) {
@@ -857,7 +871,7 @@
857
871
  return false;
858
872
  }
859
873
  zzfxParams = zzfxParams || instance.DEFAULT_SFX;
860
- if (pitchSlide > 0 || volumeFactor !== 1) {
874
+ if (pitchSlide !== 0 || volumeFactor !== 1) {
861
875
  zzfxParams = zzfxParams.slice();
862
876
  zzfxParams[0] = volumeFactor * (zzfxParams[0] || 1);
863
877
  zzfxParams[10] = ~~zzfxParams[10] + pitchSlide;
@@ -924,7 +938,7 @@
924
938
  assert(isFinite(y2), "colcirc: 5th param must be a number");
925
939
  assert(isFinite(r2), "colcirc: 6th param must be a number");
926
940
  }
927
- return (x2 - x1) ** 2 + (y2 - y1) ** 2 <= (r1 + r2) ** 2;
941
+ return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) <= (r1 + r2) * (r1 + r2);
928
942
  },
929
943
  /** PLUGINS API */
930
944
  /**
@@ -1015,7 +1029,6 @@
1015
1029
  "setvar: 1st param must be a string"
1016
1030
  );
1017
1031
  if (value == null) {
1018
- console.warn(`setvar: key "${key}" was defined as ${value}`);
1019
1032
  }
1020
1033
  }
1021
1034
  instance[key] = value;
@@ -1063,8 +1076,7 @@
1063
1076
  "setfps: 1st param must be a positive number"
1064
1077
  );
1065
1078
  }
1066
- _fixedDeltaTime = 1 / ~~value;
1067
- _accumulated = 0;
1079
+ _deltaTime = 1 / ~~value;
1068
1080
  },
1069
1081
  /**
1070
1082
  * Stops the litecanvas instance and remove all event listeners.
@@ -1074,7 +1086,8 @@
1074
1086
  for (const removeListener of _browserEventListeners) {
1075
1087
  removeListener();
1076
1088
  }
1077
- _focused = _events = false;
1089
+ cancelAnimationFrame(_rafid);
1090
+ _events = false;
1078
1091
  if (_global) {
1079
1092
  for (const key in instance) {
1080
1093
  delete root[key];
@@ -1231,38 +1244,42 @@
1231
1244
  }
1232
1245
  if (settings.pauseOnBlur) {
1233
1246
  on(root, "blur", () => {
1234
- _focused = false;
1247
+ _rafid = cancelAnimationFrame(_rafid);
1235
1248
  });
1236
1249
  on(root, "focus", () => {
1237
- _focused = true;
1238
- raf(drawFrame);
1250
+ if (!_rafid) {
1251
+ _lastFrameTime = performance.now();
1252
+ _rafid = raf(drawFrame);
1253
+ }
1239
1254
  });
1240
1255
  }
1241
1256
  instance.setfps(60);
1242
1257
  instance.emit("init", instance);
1243
1258
  _lastFrameTime = performance.now();
1244
- raf(drawFrame);
1259
+ _rafid = raf(drawFrame);
1245
1260
  }
1246
1261
  function drawFrame(now) {
1247
- let shouldRender = !_animated, frameTime = (now - _lastFrameTime) / 1e3, frameTimeMax = _fixedDeltaTime * 5;
1248
- _accumulated += frameTime > frameTimeMax ? frameTimeMax : frameTime;
1262
+ if (_animated) {
1263
+ _rafid = raf(drawFrame);
1264
+ }
1265
+ let updated = 0, frameTime = (now - _lastFrameTime) / 1e3;
1266
+ _accumulated += frameTime;
1249
1267
  _lastFrameTime = now;
1250
- while (_accumulated >= _fixedDeltaTime) {
1251
- instance.emit("update", _fixedDeltaTime * _timeScale);
1268
+ if (!_animated) {
1269
+ _accumulated = _deltaTime;
1270
+ }
1271
+ for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
1272
+ instance.emit("update", _deltaTime * _timeScale);
1252
1273
  instance.setvar(
1253
1274
  "ELAPSED",
1254
- instance.ELAPSED + _fixedDeltaTime * _timeScale
1275
+ instance.ELAPSED + _deltaTime * _timeScale
1255
1276
  );
1256
- _accumulated -= _fixedDeltaTime;
1257
- shouldRender = true;
1277
+ updated++;
1258
1278
  }
1259
- if (shouldRender) {
1279
+ if (updated) {
1260
1280
  instance.textalign("start", "top");
1261
1281
  instance.emit("draw");
1262
1282
  }
1263
- if (_focused && _animated) {
1264
- raf(drawFrame);
1265
- }
1266
1283
  }
1267
1284
  function setupCanvas() {
1268
1285
  _canvas = "string" === typeof _canvas ? document.querySelector(_canvas) : _canvas;
package/dist/dist.js CHANGED
@@ -63,7 +63,7 @@
63
63
  animate: true
64
64
  };
65
65
  settings = Object.assign(defaults, settings);
66
- let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _fullscreen = settings.fullscreen, _autoscale = settings.autoscale, _animated = settings.animate, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fixedDeltaTime, _accumulated, _focused = true, _fontFamily = "sans-serif", _fontSize = 32, _rng_seed = Date.now(), _global = settings.global, _events = {
66
+ let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _fullscreen = settings.fullscreen, _autoscale = settings.autoscale, _animated = settings.animate, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _deltaTime, _accumulated = 0, _rafid, _fontFamily = "sans-serif", _fontSize = 32, _rng_seed = Date.now(), _global = settings.global, _events = {
67
67
  init: null,
68
68
  update: null,
69
69
  draw: null,
@@ -307,7 +307,7 @@
307
307
  },
308
308
  /** BASIC GRAPHICS API */
309
309
  /**
310
- * Clear the game screen
310
+ * Clear the game screen with an optional color
311
311
  *
312
312
  * @param {number?} color The background color (index) or null (for transparent)
313
313
  */
@@ -315,14 +315,19 @@
315
315
  if (false) {
316
316
  assert(
317
317
  null == color || isFinite(color) && color >= 0,
318
- "cls: 1st param must be a number"
318
+ "cls: 1st param must be a positive number or zero or null"
319
319
  );
320
320
  }
321
- let width = _ctx.canvas.width, height = _ctx.canvas.height;
322
321
  if (null == color) {
323
- _ctx.clearRect(0, 0, width, height);
322
+ _ctx.clearRect(0, 0, _ctx.canvas.width, _ctx.canvas.height);
324
323
  } else {
325
- instance.rectfill(0, 0, width, height, color);
324
+ instance.rectfill(
325
+ 0,
326
+ 0,
327
+ _ctx.canvas.width,
328
+ _ctx.canvas.height,
329
+ color
330
+ );
326
331
  }
327
332
  },
328
333
  /**
@@ -588,11 +593,20 @@
588
593
  textalign(align, baseline) {
589
594
  if (false) {
590
595
  assert(
591
- null == align || "string" === typeof align,
596
+ null == align || ["left", "right", "center", "start", "end"].includes(
597
+ align
598
+ ),
592
599
  "textalign: 1st param must be a string"
593
600
  );
594
601
  assert(
595
- null == baseline || "string" === typeof baseline,
602
+ null == baseline || [
603
+ "top",
604
+ "bottom",
605
+ "middle",
606
+ "hanging",
607
+ "alphabetic",
608
+ "ideographic"
609
+ ].includes(baseline),
596
610
  "textalign: 2nd param must be a string"
597
611
  );
598
612
  }
@@ -667,8 +681,8 @@
667
681
  /**
668
682
  * Get or set the canvas context 2D
669
683
  *
670
- * @param {CanvasRenderingContext2D} [context]
671
- * @returns {CanvasRenderingContext2D}
684
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
685
+ * @returns {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D}
672
686
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
673
687
  */
674
688
  ctx(context) {
@@ -852,7 +866,7 @@
852
866
  return false;
853
867
  }
854
868
  zzfxParams = zzfxParams || instance.DEFAULT_SFX;
855
- if (pitchSlide > 0 || volumeFactor !== 1) {
869
+ if (pitchSlide !== 0 || volumeFactor !== 1) {
856
870
  zzfxParams = zzfxParams.slice();
857
871
  zzfxParams[0] = volumeFactor * (zzfxParams[0] || 1);
858
872
  zzfxParams[10] = ~~zzfxParams[10] + pitchSlide;
@@ -919,7 +933,7 @@
919
933
  assert(isFinite(y2), "colcirc: 5th param must be a number");
920
934
  assert(isFinite(r2), "colcirc: 6th param must be a number");
921
935
  }
922
- return (x2 - x1) ** 2 + (y2 - y1) ** 2 <= (r1 + r2) ** 2;
936
+ return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) <= (r1 + r2) * (r1 + r2);
923
937
  },
924
938
  /** PLUGINS API */
925
939
  /**
@@ -1010,7 +1024,6 @@
1010
1024
  "setvar: 1st param must be a string"
1011
1025
  );
1012
1026
  if (value == null) {
1013
- console.warn(`setvar: key "${key}" was defined as ${value}`);
1014
1027
  }
1015
1028
  }
1016
1029
  instance[key] = value;
@@ -1058,8 +1071,7 @@
1058
1071
  "setfps: 1st param must be a positive number"
1059
1072
  );
1060
1073
  }
1061
- _fixedDeltaTime = 1 / ~~value;
1062
- _accumulated = 0;
1074
+ _deltaTime = 1 / ~~value;
1063
1075
  },
1064
1076
  /**
1065
1077
  * Stops the litecanvas instance and remove all event listeners.
@@ -1069,7 +1081,8 @@
1069
1081
  for (const removeListener of _browserEventListeners) {
1070
1082
  removeListener();
1071
1083
  }
1072
- _focused = _events = false;
1084
+ cancelAnimationFrame(_rafid);
1085
+ _events = false;
1073
1086
  if (_global) {
1074
1087
  for (const key in instance) {
1075
1088
  delete root[key];
@@ -1226,38 +1239,42 @@
1226
1239
  }
1227
1240
  if (settings.pauseOnBlur) {
1228
1241
  on(root, "blur", () => {
1229
- _focused = false;
1242
+ _rafid = cancelAnimationFrame(_rafid);
1230
1243
  });
1231
1244
  on(root, "focus", () => {
1232
- _focused = true;
1233
- raf(drawFrame);
1245
+ if (!_rafid) {
1246
+ _lastFrameTime = performance.now();
1247
+ _rafid = raf(drawFrame);
1248
+ }
1234
1249
  });
1235
1250
  }
1236
1251
  instance.setfps(60);
1237
1252
  instance.emit("init", instance);
1238
1253
  _lastFrameTime = performance.now();
1239
- raf(drawFrame);
1254
+ _rafid = raf(drawFrame);
1240
1255
  }
1241
1256
  function drawFrame(now) {
1242
- let shouldRender = !_animated, frameTime = (now - _lastFrameTime) / 1e3, frameTimeMax = _fixedDeltaTime * 5;
1243
- _accumulated += frameTime > frameTimeMax ? frameTimeMax : frameTime;
1257
+ if (_animated) {
1258
+ _rafid = raf(drawFrame);
1259
+ }
1260
+ let updated = 0, frameTime = (now - _lastFrameTime) / 1e3;
1261
+ _accumulated += frameTime;
1244
1262
  _lastFrameTime = now;
1245
- while (_accumulated >= _fixedDeltaTime) {
1246
- instance.emit("update", _fixedDeltaTime * _timeScale);
1263
+ if (!_animated) {
1264
+ _accumulated = _deltaTime;
1265
+ }
1266
+ for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
1267
+ instance.emit("update", _deltaTime * _timeScale);
1247
1268
  instance.setvar(
1248
1269
  "ELAPSED",
1249
- instance.ELAPSED + _fixedDeltaTime * _timeScale
1270
+ instance.ELAPSED + _deltaTime * _timeScale
1250
1271
  );
1251
- _accumulated -= _fixedDeltaTime;
1252
- shouldRender = true;
1272
+ updated++;
1253
1273
  }
1254
- if (shouldRender) {
1274
+ if (updated) {
1255
1275
  instance.textalign("start", "top");
1256
1276
  instance.emit("draw");
1257
1277
  }
1258
- if (_focused && _animated) {
1259
- raf(drawFrame);
1260
- }
1261
1278
  }
1262
1279
  function setupCanvas() {
1263
1280
  _canvas = "string" === typeof _canvas ? document.querySelector(_canvas) : _canvas;
package/dist/dist.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e=new AudioContext,t=(t=1,a=.05,l=220,n=0,i=0,r=.1,o=0,s=1,c=0,f=0,u=0,p=0,d=0,h=0,g=0,m=0,v=0,E=1,b=0,T=0,w=0)=>{let x=Math,y=2*x.PI,D=c*=500*y/44100/44100,H=l*=(1-a+2*a*x.random(a=[]))*y/44100,I=0,S=0,k=0,A=1,C=0,L=0,X=0,O=w<0?-1:1,z=y*O*w*2/44100,M=x.cos(z),P=x.sin,Y=P(z)/4,W=1+Y,F=-2*M/W,_=(1-Y)/W,R=(1+O*M)/2/W,G=-(O+M)/W,N=0,B=0,U=0,j=0;for(n=44100*n+9,b*=44100,i*=44100,r*=44100,v*=44100,f*=500*y/85766121e6,g*=y/44100,u*=y/44100,p*=44100,d=44100*d|0,t*=.3*(globalThis.zzfxV||1),O=n+b+i+r+v|0;k<O;a[k++]=X*t)++L%(100*m|0)||(X=o?1<o?2<o?3<o?P(I*I):x.max(x.min(x.tan(I),1),-1):1-(2*I/y%2+2)%2:1-4*x.abs(x.round(I/y)-I/y):P(I),X=(d?1-T+T*P(y*k/d):1)*(X<0?-1:1)*x.abs(X)**s*(k<n?k/n:k<n+b?1-(k-n)/b*(1-E):k<n+b+i?E:k<O-v?(O-k-v)/r*E:0),X=v?X/2+(v>k?0:(k<O-v?1:(O-k)/v)*a[k-v|0]/2/t):X,w&&(X=j=R*N+G*(N=B)+R*(B=X)-_*U-F*(U=j))),I+=(z=(l+=c+=f)*x.cos(g*S++))+z*h*P(k**5),A&&++A>p&&(l+=u,H+=u,A=0),!d||++C%d||(l=H,c=D,A=A||1);(t=e.createBuffer(1,O,44100)).getChannelData(0).set(a),(l=e.createBufferSource()).buffer=t,l.connect(e.destination),l.start()},a=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(e={}){let l=globalThis,n=Math.PI,i=2*n,r=requestAnimationFrame,o=[],s=(e,t,a)=>{e.addEventListener(t,a,!1),o.push(()=>e.removeEventListener(t,a,!1))};e=Object.assign({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 c=!1,f=[],u=e.canvas||document.createElement("canvas"),p=e.fullscreen,d=e.autoscale,h=e.animate,g=1,m,v=.5,E=1,b,T,w,x=!0,y="sans-serif",D=32,H=Date.now(),I=e.global,S={init:null,update:null,draw:null,resized:null,tap:null,untap:null,tapping:null,tapped:null},k={settings:Object.assign({},e),colors:a},A={WIDTH:e.width,HEIGHT:e.height||e.width,CANVAS:null,ELAPSED:0,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?A.clamp(r,l,n):r},norm:(e,t,a)=>A.map(e,t,a,0,1),rand:(e=0,t=1)=>(H=(1664525*H+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>Math.floor(A.rand(e,t+1)),seed:e=>null==e?H:H=~~e,cls(e){let t=m.canvas.width,a=m.canvas.height;null==e?m.clearRect(0,0,t,a):A.rectfill(0,0,t,a,e)},rect(e,t,a,l,n,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e-v,~~t-v,~~a+2*v,~~l+2*v,i),A.stroke(n)},rectfill(e,t,a,l,n,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),A.fill(n)},circ(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,~~a,0,i),A.stroke(l)},circfill(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,~~a,0,i),A.fill(l)},line(e,t,a,l,n){m.beginPath();let i=.5*(0!==v&&~~e==~~a),r=.5*(0!==v&&~~t==~~l);m.moveTo(~~e+i,~~t+r),m.lineTo(~~a+i,~~l+r),A.stroke(n)},linewidth(e){m.lineWidth=~~e,v=.5*(~~e%2!=0)},linedash(e,t=0){m.setLineDash(e),m.lineDashOffset=t},text(e,t,a,l=3,n="normal"){m.font=`${n} ${D}px ${y}`,m.fillStyle=A.getcolor(l),m.fillText(a,~~e,~~t)},textfont(e){y=e},textsize(e){D=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,l={}){let n=l.canvas||new OffscreenCanvas(1,1),i=l.scale||1,r=m;if(n.width=e*i,n.height=t*i,(m=n.getContext("2d")).scale(i,i),a.push){let e=0,t=0;for(let l of(m.imageSmoothingEnabled=!1,a)){for(let a of l)" "!==a&&"."!==a&&A.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(m);return m=r,n},ctx:e=>(e&&(m=e),m),push:()=>m.save(),pop:()=>m.restore(),translate:(e,t)=>m.translate(~~e,~~t),scale:(e,t)=>m.scale(e,t||e),rotate:e=>m.rotate(e),alpha(e){m.globalAlpha=A.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){m.fillStyle=A.getcolor(e),t?m.fill(t):m.fill()},stroke(e,t){m.strokeStyle=A.getcolor(e),t?m.stroke(t):m.stroke()},clip(e){m.clip(e)},sfx:(e,a=0,n=1)=>!(l.zzfxV<=0)&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||A.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={}){c?z(e,t):f.push([e,t])},listen:(e,t)=>(S[e]=S[e]||new Set,S[e].add(t),()=>S[e].delete(t)),emit(e,t,a,l,n){O("before:"+e,t,a,l,n),O(e,t,a,l,n),O("after:"+e,t,a,l,n)},getcolor:e=>a[~~e%a.length],setvar(e,t){A[e]=t,I&&(l[e]=t)},resize(e,t){A.setvar("WIDTH",u.width=e),A.setvar("HEIGHT",u.height=t),X()},timescale(e){E=e},setfps(e){T=1/~~e,w=0},quit(){for(let e of(A.emit("quit"),o))e();if(x=S=!1,I){for(let e in A)delete l[e];delete l.__litecanvas}}};for(let e of["sin","cos","atan2","hypot","tan","abs","ceil","round","floor","trunc","min","max","pow","sqrt","sign","exp"])A[e]=Math[e];function C(){c=!0;let t=e.loop?e.loop:l;for(let e in S)t[e]&&A.listen(e,t[e]);for(let[e,t]of f)z(e,t);if((p||d)&&s(l,"resize",X),X(),e.tapEvents){let e=(e,t)=>[(e-u.offsetLeft)/g,(t-u.offsetTop)/g],t=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;s(u,"mousedown",t=>{t.preventDefault();let[l,n]=e(t.pageX,t.pageY);A.emit("tap",l,n,0),a(0,l,n),r=!0}),s(u,"mousemove",t=>{t.preventDefault();let[a,l]=e(t.pageX,t.pageY);A.setvar("MOUSEX",a),A.setvar("MOUSEY",l),r&&(A.emit("tapping",a,l,0),n(0,a,l))}),s(u,"mouseup",a=>{a.preventDefault();let l=t.get(0),[n,o]=e(a.pageX,a.pageY);i(l)&&A.emit("tapped",l.startX,l.startY,0),A.emit("untap",n,o,0),t.delete(0),r=!1}),s(u,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l.pageX,l.pageY);A.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),s(u,"touchmove",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,l]=e(a.pageX,a.pageY);A.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let o=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)&&A.emit("tapped",l.startX,l.startY,e),A.emit("untap",l.x,l.y,e),t.delete(e))};s(u,"touchend",o),s(u,"touchcancel",o),s(l,"blur",()=>{for(let[e,a]of(r=!1,t))A.emit("untap",a.x,a.y,e),t.delete(e)})}if(e.keyboardEvents){let e=new Set;A.setvar("iskeydown",t=>"any"===t?e.size>0:e.has(t.toLowerCase())),s(l,"keydown",t=>{e.add(t.key.toLowerCase())}),s(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),s(l,"blur",()=>e.clear())}e.pauseOnBlur&&(s(l,"blur",()=>{x=!1}),s(l,"focus",()=>{x=!0,r(L)})),A.setfps(60),A.emit("init",A),b=performance.now(),r(L)}function L(e){let t=!h,a=(e-b)/1e3,l=5*T;for(w+=a>l?l:a,b=e;w>=T;)A.emit("update",T*E),A.setvar("ELAPSED",A.ELAPSED+T*E),w-=T,t=!0;t&&(A.textalign("start","top"),A.emit("draw")),x&&h&&r(L)}function X(){let t=l.innerWidth,a=l.innerHeight,n=u.style;n.display="block",p?(n.position="absolute",n.inset=0,A.setvar("WIDTH",u.width=t),A.setvar("HEIGHT",u.height=a)):d&&(n.margin="auto",g=Math.min(t/A.WIDTH,a/A.HEIGHT),g=(e.pixelart?~~g:g)||1,n.width=A.WIDTH*g+"px",n.height=A.HEIGHT*g+"px"),A.setvar("CENTERX",A.WIDTH/2),A.setvar("CENTERY",A.HEIGHT/2),(!e.antialias||e.pixelart)&&(m.imageSmoothingEnabled=!1,u.style.imageRendering="pixelated"),A.emit("resized",g),h||r(L)}function O(e,t,a,l,n){if(S[e])for(let i of S[e])i(t,a,l,n)}function z(e,t){let a=e(A,k,t);if("object"==typeof a)for(let e of Object.keys(a))A.setvar(e,a[e])}if(I){if(l.__litecanvas)throw"global litecanvas already instantiated";Object.assign(l,A),l.__litecanvas=A}return u="string"==typeof u?document.querySelector(u):u,A.setvar("CANVAS",u),m=u.getContext("2d"),s(u,"click",()=>l.focus()),A.WIDTH>0&&(p=!1),u.style="",u.width=A.WIDTH,u.height=A.HEIGHT||A.WIDTH,u.parentNode||document.body.appendChild(u),"loading"===document.readyState?s(l,"DOMContentLoaded",()=>r(C)):r(C),A}})();
1
+ (()=>{var e=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,h=0,g=0,m=0,v=0,E=1,b=0,w=0,T=0)=>{let x=Math,y=2*x.PI,D=c*=500*y/44100/44100,H=l*=(1-a+2*a*x.random(a=[]))*y/44100,I=0,S=0,A=0,k=1,C=0,L=0,X=0,O=T<0?-1:1,z=y*O*T*2/44100,M=x.cos(z),P=x.sin,Y=P(z)/4,F=1+Y,W=-2*M/F,_=(1-Y)/F,R=(1+O*M)/2/F,G=-(O+M)/F,N=0,B=0,U=0,j=0;for(n=44100*n+9,b*=44100,i*=44100,r*=44100,v*=44100,f*=500*y/85766121e6,g*=y/44100,p*=y/44100,u*=44100,d=44100*d|0,t*=.3*(globalThis.zzfxV||1),O=n+b+i+r+v|0;A<O;a[A++]=X*t)++L%(100*m|0)||(X=o?1<o?2<o?3<o?P(I*I):x.max(x.min(x.tan(I),1),-1):1-(2*I/y%2+2)%2:1-4*x.abs(x.round(I/y)-I/y):P(I),X=(d?1-w+w*P(y*A/d):1)*(X<0?-1:1)*x.abs(X)**s*(A<n?A/n:A<n+b?1-(A-n)/b*(1-E):A<n+b+i?E:A<O-v?(O-A-v)/r*E:0),X=v?X/2+(v>A?0:(A<O-v?1:(O-A)/v)*a[A-v|0]/2/t):X,T&&(X=j=R*N+G*(N=B)+R*(B=X)-_*U-W*(U=j))),I+=(z=(l+=c+=f)*x.cos(g*S++))+z*h*P(A**5),k&&++k>u&&(l+=p,H+=p,k=0),!d||++C%d||(l=H,c=D,k=k||1);(t=e.createBuffer(1,O,44100)).getChannelData(0).set(a),(l=e.createBufferSource()).buffer=t,l.connect(e.destination),l.start()},a=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(e={}){let l=globalThis,n=Math.PI,i=2*n,r=requestAnimationFrame,o=[],s=(e,t,a)=>{e.addEventListener(t,a,!1),o.push(()=>e.removeEventListener(t,a,!1))};e=Object.assign({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 c=!1,f=[],p=e.canvas||document.createElement("canvas"),u=e.fullscreen,d=e.autoscale,h=e.animate,g=1,m,v=.5,E=1,b,w,T=0,x,y="sans-serif",D=32,H=Date.now(),I=e.global,S={init:null,update:null,draw:null,resized:null,tap:null,untap:null,tapping:null,tapped:null},A={settings:Object.assign({},e),colors:a},k={WIDTH:e.width,HEIGHT:e.height||e.width,CANVAS:null,ELAPSED:0,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?k.clamp(r,l,n):r},norm:(e,t,a)=>k.map(e,t,a,0,1),rand:(e=0,t=1)=>(H=(1664525*H+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>Math.floor(k.rand(e,t+1)),seed:e=>null==e?H:H=~~e,cls(e){null==e?m.clearRect(0,0,m.canvas.width,m.canvas.height):k.rectfill(0,0,m.canvas.width,m.canvas.height,e)},rect(e,t,a,l,n,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e-v,~~t-v,~~a+2*v,~~l+2*v,i),k.stroke(n)},rectfill(e,t,a,l,n,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),k.fill(n)},circ(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,~~a,0,i),k.stroke(l)},circfill(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,~~a,0,i),k.fill(l)},line(e,t,a,l,n){m.beginPath();let i=.5*(0!==v&&~~e==~~a),r=.5*(0!==v&&~~t==~~l);m.moveTo(~~e+i,~~t+r),m.lineTo(~~a+i,~~l+r),k.stroke(n)},linewidth(e){m.lineWidth=~~e,v=.5*(~~e%2!=0)},linedash(e,t=0){m.setLineDash(e),m.lineDashOffset=t},text(e,t,a,l=3,n="normal"){m.font=`${n} ${D}px ${y}`,m.fillStyle=k.getcolor(l),m.fillText(a,~~e,~~t)},textfont(e){y=e},textsize(e){D=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,l={}){let n=l.canvas||new OffscreenCanvas(1,1),i=l.scale||1,r=m;if(n.width=e*i,n.height=t*i,(m=n.getContext("2d")).scale(i,i),a.push){let e=0,t=0;for(let l of(m.imageSmoothingEnabled=!1,a)){for(let a of l)" "!==a&&"."!==a&&k.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(m);return m=r,n},ctx:e=>(e&&(m=e),m),push:()=>m.save(),pop:()=>m.restore(),translate:(e,t)=>m.translate(~~e,~~t),scale:(e,t)=>m.scale(e,t||e),rotate:e=>m.rotate(e),alpha(e){m.globalAlpha=k.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){m.fillStyle=k.getcolor(e),t?m.fill(t):m.fill()},stroke(e,t){m.strokeStyle=k.getcolor(e),t?m.stroke(t):m.stroke()},clip(e){m.clip(e)},sfx:(e,a=0,n=1)=>!(l.zzfxV<=0)&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||k.DEFAULT_SFX,(0!==a||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)*(l-e)+(n-t)*(n-t)<=(a+i)*(a+i),use(e,t={}){c?z(e,t):f.push([e,t])},listen:(e,t)=>(S[e]=S[e]||new Set,S[e].add(t),()=>S[e].delete(t)),emit(e,t,a,l,n){O("before:"+e,t,a,l,n),O(e,t,a,l,n),O("after:"+e,t,a,l,n)},getcolor:e=>a[~~e%a.length],setvar(e,t){k[e]=t,I&&(l[e]=t)},resize(e,t){k.setvar("WIDTH",p.width=e),k.setvar("HEIGHT",p.height=t),X()},timescale(e){E=e},setfps(e){w=1/~~e},quit(){for(let e of(k.emit("quit"),o))e();if(cancelAnimationFrame(x),S=!1,I){for(let e in k)delete l[e];delete l.__litecanvas}}};for(let e of["sin","cos","atan2","hypot","tan","abs","ceil","round","floor","trunc","min","max","pow","sqrt","sign","exp"])k[e]=Math[e];function C(){c=!0;let t=e.loop?e.loop:l;for(let e in S)t[e]&&k.listen(e,t[e]);for(let[e,t]of f)z(e,t);if((u||d)&&s(l,"resize",X),X(),e.tapEvents){let e=(e,t)=>[(e-p.offsetLeft)/g,(t-p.offsetTop)/g],t=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;s(p,"mousedown",t=>{t.preventDefault();let[l,n]=e(t.pageX,t.pageY);k.emit("tap",l,n,0),a(0,l,n),r=!0}),s(p,"mousemove",t=>{t.preventDefault();let[a,l]=e(t.pageX,t.pageY);k.setvar("MOUSEX",a),k.setvar("MOUSEY",l),r&&(k.emit("tapping",a,l,0),n(0,a,l))}),s(p,"mouseup",a=>{a.preventDefault();let l=t.get(0),[n,o]=e(a.pageX,a.pageY);i(l)&&k.emit("tapped",l.startX,l.startY,0),k.emit("untap",n,o,0),t.delete(0),r=!1}),s(p,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l.pageX,l.pageY);k.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),s(p,"touchmove",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,l]=e(a.pageX,a.pageY);k.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let o=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)&&k.emit("tapped",l.startX,l.startY,e),k.emit("untap",l.x,l.y,e),t.delete(e))};s(p,"touchend",o),s(p,"touchcancel",o),s(l,"blur",()=>{for(let[e,a]of(r=!1,t))k.emit("untap",a.x,a.y,e),t.delete(e)})}if(e.keyboardEvents){let e=new Set;k.setvar("iskeydown",t=>"any"===t?e.size>0:e.has(t.toLowerCase())),s(l,"keydown",t=>{e.add(t.key.toLowerCase())}),s(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),s(l,"blur",()=>e.clear())}e.pauseOnBlur&&(s(l,"blur",()=>{x=cancelAnimationFrame(x)}),s(l,"focus",()=>{x||(b=performance.now(),x=r(L))})),k.setfps(60),k.emit("init",k),b=performance.now(),x=r(L)}function L(e){h&&(x=r(L));let t=0;for(T+=(e-b)/1e3,b=e,h||(T=w);T>=w;T-=w)k.emit("update",w*E),k.setvar("ELAPSED",k.ELAPSED+w*E),t++;t&&(k.textalign("start","top"),k.emit("draw"))}function X(){let t=l.innerWidth,a=l.innerHeight,n=p.style;n.display="block",u?(n.position="absolute",n.inset=0,k.setvar("WIDTH",p.width=t),k.setvar("HEIGHT",p.height=a)):d&&(n.margin="auto",g=Math.min(t/k.WIDTH,a/k.HEIGHT),g=(e.pixelart?~~g:g)||1,n.width=k.WIDTH*g+"px",n.height=k.HEIGHT*g+"px"),k.setvar("CENTERX",k.WIDTH/2),k.setvar("CENTERY",k.HEIGHT/2),(!e.antialias||e.pixelart)&&(m.imageSmoothingEnabled=!1,p.style.imageRendering="pixelated"),k.emit("resized",g),h||r(L)}function O(e,t,a,l,n){if(S[e])for(let i of S[e])i(t,a,l,n)}function z(e,t){let a=e(k,A,t);if("object"==typeof a)for(let e of Object.keys(a))k.setvar(e,a[e])}if(I){if(l.__litecanvas)throw"global litecanvas already instantiated";Object.assign(l,k),l.__litecanvas=k}return p="string"==typeof p?document.querySelector(p):p,k.setvar("CANVAS",p),m=p.getContext("2d"),s(p,"click",()=>l.focus()),k.WIDTH>0&&(u=!1),p.style="",p.width=k.WIDTH,p.height=k.HEIGHT||k.WIDTH,p.parentNode||document.body.appendChild(p),"loading"===document.readyState?s(l,"DOMContentLoaded",()=>r(C)):r(C),k}})();
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.74.0",
3
+ "version": "0.74.2",
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>",
7
7
  "contributors": [],
8
8
  "devDependencies": {
9
- "@swc/core": "^1.10.16",
9
+ "@swc/core": "^1.11.4",
10
10
  "ava": "^6.2.0",
11
11
  "esbuild": "^0.25.0",
12
12
  "gzip-size": "^7.0.0",
13
- "prettier": "^3.5.1"
13
+ "prettier": "^3.5.2"
14
14
  },
15
15
  "homepage": "https://litecanvas.github.io/about.html",
16
16
  "repository": {
package/src/index.js CHANGED
@@ -67,11 +67,11 @@ export default function litecanvas(settings = {}) {
67
67
  /** @type {number} */
68
68
  _lastFrameTime,
69
69
  /** @type {number} */
70
- _fixedDeltaTime,
70
+ _deltaTime,
71
71
  /** @type {number} */
72
- _accumulated,
72
+ _accumulated = 0,
73
73
  /** @type {number} */
74
- _focused = true,
74
+ _rafid,
75
75
  /** @type {string} */
76
76
  _fontFamily = 'sans-serif',
77
77
  /** @type {number} */
@@ -361,7 +361,7 @@ export default function litecanvas(settings = {}) {
361
361
 
362
362
  /** BASIC GRAPHICS API */
363
363
  /**
364
- * Clear the game screen
364
+ * Clear the game screen with an optional color
365
365
  *
366
366
  * @param {number?} color The background color (index) or null (for transparent)
367
367
  */
@@ -369,15 +369,19 @@ export default function litecanvas(settings = {}) {
369
369
  if (DEV_BUILD) {
370
370
  assert(
371
371
  null == color || (isFinite(color) && color >= 0),
372
- 'cls: 1st param must be a number'
372
+ 'cls: 1st param must be a positive number or zero or null'
373
373
  )
374
374
  }
375
- let width = _ctx.canvas.width,
376
- height = _ctx.canvas.height
377
375
  if (null == color) {
378
- _ctx.clearRect(0, 0, width, height)
376
+ _ctx.clearRect(0, 0, _ctx.canvas.width, _ctx.canvas.height)
379
377
  } else {
380
- instance.rectfill(0, 0, width, height, color)
378
+ instance.rectfill(
379
+ 0,
380
+ 0,
381
+ _ctx.canvas.width,
382
+ _ctx.canvas.height,
383
+ color
384
+ )
381
385
  }
382
386
  },
383
387
 
@@ -665,11 +669,22 @@ export default function litecanvas(settings = {}) {
665
669
  textalign(align, baseline) {
666
670
  if (DEV_BUILD) {
667
671
  assert(
668
- null == align || 'string' === typeof align,
672
+ null == align ||
673
+ ['left', 'right', 'center', 'start', 'end'].includes(
674
+ align
675
+ ),
669
676
  'textalign: 1st param must be a string'
670
677
  )
671
678
  assert(
672
- null == baseline || 'string' === typeof baseline,
679
+ null == baseline ||
680
+ [
681
+ 'top',
682
+ 'bottom',
683
+ 'middle',
684
+ 'hanging',
685
+ 'alphabetic',
686
+ 'ideographic',
687
+ ].includes(baseline),
673
688
  'textalign: 2nd param must be a string'
674
689
  )
675
690
  }
@@ -759,8 +774,8 @@ export default function litecanvas(settings = {}) {
759
774
  /**
760
775
  * Get or set the canvas context 2D
761
776
  *
762
- * @param {CanvasRenderingContext2D} [context]
763
- * @returns {CanvasRenderingContext2D}
777
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
778
+ * @returns {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D}
764
779
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
765
780
  */
766
781
  ctx(context) {
@@ -965,7 +980,7 @@ export default function litecanvas(settings = {}) {
965
980
  zzfxParams = zzfxParams || instance.DEFAULT_SFX
966
981
 
967
982
  // if has other arguments, copy the sound to not change the original
968
- if (pitchSlide > 0 || volumeFactor !== 1) {
983
+ if (pitchSlide !== 0 || volumeFactor !== 1) {
969
984
  zzfxParams = zzfxParams.slice()
970
985
  zzfxParams[0] = volumeFactor * (zzfxParams[0] || 1)
971
986
  zzfxParams[10] = ~~zzfxParams[10] + pitchSlide
@@ -1037,7 +1052,10 @@ export default function litecanvas(settings = {}) {
1037
1052
  assert(isFinite(y2), 'colcirc: 5th param must be a number')
1038
1053
  assert(isFinite(r2), 'colcirc: 6th param must be a number')
1039
1054
  }
1040
- return (x2 - x1) ** 2 + (y2 - y1) ** 2 <= (r1 + r2) ** 2
1055
+ return (
1056
+ (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) <=
1057
+ (r1 + r2) * (r1 + r2)
1058
+ )
1041
1059
  },
1042
1060
 
1043
1061
  /** PLUGINS API */
@@ -1188,8 +1206,7 @@ export default function litecanvas(settings = {}) {
1188
1206
  'setfps: 1st param must be a positive number'
1189
1207
  )
1190
1208
  }
1191
- _fixedDeltaTime = 1 / ~~value
1192
- _accumulated = 0
1209
+ _deltaTime = 1 / ~~value
1193
1210
  },
1194
1211
 
1195
1212
  /**
@@ -1200,7 +1217,8 @@ export default function litecanvas(settings = {}) {
1200
1217
  for (const removeListener of _browserEventListeners) {
1201
1218
  removeListener()
1202
1219
  }
1203
- _focused = _events = false
1220
+ cancelAnimationFrame(_rafid)
1221
+ _events = false
1204
1222
  if (_global) {
1205
1223
  for (const key in instance) {
1206
1224
  delete root[key]
@@ -1410,12 +1428,14 @@ export default function litecanvas(settings = {}) {
1410
1428
  // listen browser focus/blur events and pause the update/draw loop
1411
1429
  if (settings.pauseOnBlur) {
1412
1430
  on(root, 'blur', () => {
1413
- _focused = false
1431
+ _rafid = cancelAnimationFrame(_rafid)
1414
1432
  })
1415
1433
 
1416
1434
  on(root, 'focus', () => {
1417
- _focused = true
1418
- raf(drawFrame)
1435
+ if (!_rafid) {
1436
+ _lastFrameTime = performance.now()
1437
+ _rafid = raf(drawFrame)
1438
+ }
1419
1439
  })
1420
1440
  }
1421
1441
 
@@ -1425,37 +1445,40 @@ export default function litecanvas(settings = {}) {
1425
1445
  instance.emit('init', instance)
1426
1446
 
1427
1447
  _lastFrameTime = performance.now()
1428
- raf(drawFrame)
1448
+ _rafid = raf(drawFrame)
1429
1449
  }
1430
1450
 
1431
1451
  /**
1432
- * @param {number} now
1452
+ * @param {DOMHighResTimeStamp} now
1433
1453
  */
1434
1454
  function drawFrame(now) {
1435
- let shouldRender = !_animated,
1436
- frameTime = (now - _lastFrameTime) / 1000,
1437
- frameTimeMax = _fixedDeltaTime * 5
1455
+ if (_animated) {
1456
+ _rafid = raf(drawFrame)
1457
+ }
1458
+
1459
+ let updated = 0,
1460
+ frameTime = (now - _lastFrameTime) / 1000
1438
1461
 
1439
- _accumulated += frameTime > frameTimeMax ? frameTimeMax : frameTime
1462
+ _accumulated += frameTime
1440
1463
  _lastFrameTime = now
1441
1464
 
1442
- while (_accumulated >= _fixedDeltaTime) {
1443
- instance.emit('update', _fixedDeltaTime * _timeScale)
1465
+ if (!_animated) {
1466
+ _accumulated = _deltaTime
1467
+ }
1468
+
1469
+ for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
1470
+ instance.emit('update', _deltaTime * _timeScale)
1444
1471
  instance.setvar(
1445
1472
  'ELAPSED',
1446
- instance.ELAPSED + _fixedDeltaTime * _timeScale
1473
+ instance.ELAPSED + _deltaTime * _timeScale
1447
1474
  )
1448
- _accumulated -= _fixedDeltaTime
1449
- shouldRender = true
1475
+ updated++
1450
1476
  }
1451
1477
 
1452
- if (shouldRender) {
1478
+ if (updated) {
1453
1479
  instance.textalign('start', 'top') // default values for textAlign & textBaseline
1454
1480
  instance.emit('draw')
1455
- }
1456
-
1457
- if (_focused && _animated) {
1458
- raf(drawFrame)
1481
+ console.log(updated)
1459
1482
  }
1460
1483
  }
1461
1484
 
package/types/index.d.ts CHANGED
@@ -214,7 +214,7 @@ declare global {
214
214
 
215
215
  /** BASIC GRAPHICS API */
216
216
  /**
217
- * Clear the game screen
217
+ * Clear the game screen with an optional color
218
218
  *
219
219
  * @param color The background color index or `null`
220
220
  */
package/types/types.d.ts CHANGED
@@ -203,7 +203,7 @@ type LitecanvasInstance = {
203
203
 
204
204
  /** BASIC GRAPHICS API */
205
205
  /**
206
- * Clear the game screen
206
+ * Clear the game screen with an optional color
207
207
  *
208
208
  * @param color The background color index or `null`
209
209
  */