litecanvas 0.74.1 → 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,
@@ -598,11 +598,20 @@
598
598
  textalign(align, baseline) {
599
599
  if (true) {
600
600
  assert(
601
- null == align || "string" === typeof align,
601
+ null == align || ["left", "right", "center", "start", "end"].includes(
602
+ align
603
+ ),
602
604
  "textalign: 1st param must be a string"
603
605
  );
604
606
  assert(
605
- null == baseline || "string" === typeof baseline,
607
+ null == baseline || [
608
+ "top",
609
+ "bottom",
610
+ "middle",
611
+ "hanging",
612
+ "alphabetic",
613
+ "ideographic"
614
+ ].includes(baseline),
606
615
  "textalign: 2nd param must be a string"
607
616
  );
608
617
  }
@@ -1020,7 +1029,6 @@
1020
1029
  "setvar: 1st param must be a string"
1021
1030
  );
1022
1031
  if (value == null) {
1023
- console.warn(`setvar: key "${key}" was defined as ${value}`);
1024
1032
  }
1025
1033
  }
1026
1034
  instance[key] = value;
@@ -1068,8 +1076,7 @@
1068
1076
  "setfps: 1st param must be a positive number"
1069
1077
  );
1070
1078
  }
1071
- _fixedDeltaTime = 1 / ~~value;
1072
- _accumulated = 0;
1079
+ _deltaTime = 1 / ~~value;
1073
1080
  },
1074
1081
  /**
1075
1082
  * Stops the litecanvas instance and remove all event listeners.
@@ -1079,7 +1086,8 @@
1079
1086
  for (const removeListener of _browserEventListeners) {
1080
1087
  removeListener();
1081
1088
  }
1082
- _focused = _events = false;
1089
+ cancelAnimationFrame(_rafid);
1090
+ _events = false;
1083
1091
  if (_global) {
1084
1092
  for (const key in instance) {
1085
1093
  delete root[key];
@@ -1236,38 +1244,42 @@
1236
1244
  }
1237
1245
  if (settings.pauseOnBlur) {
1238
1246
  on(root, "blur", () => {
1239
- _focused = false;
1247
+ _rafid = cancelAnimationFrame(_rafid);
1240
1248
  });
1241
1249
  on(root, "focus", () => {
1242
- _focused = true;
1243
- raf(drawFrame);
1250
+ if (!_rafid) {
1251
+ _lastFrameTime = performance.now();
1252
+ _rafid = raf(drawFrame);
1253
+ }
1244
1254
  });
1245
1255
  }
1246
1256
  instance.setfps(60);
1247
1257
  instance.emit("init", instance);
1248
1258
  _lastFrameTime = performance.now();
1249
- raf(drawFrame);
1259
+ _rafid = raf(drawFrame);
1250
1260
  }
1251
1261
  function drawFrame(now) {
1252
- let shouldRender = !_animated, frameTime = (now - _lastFrameTime) / 1e3, frameTimeMax = _fixedDeltaTime * 5;
1253
- _accumulated += frameTime > frameTimeMax ? frameTimeMax : frameTime;
1262
+ if (_animated) {
1263
+ _rafid = raf(drawFrame);
1264
+ }
1265
+ let updated = 0, frameTime = (now - _lastFrameTime) / 1e3;
1266
+ _accumulated += frameTime;
1254
1267
  _lastFrameTime = now;
1255
- while (_accumulated >= _fixedDeltaTime) {
1256
- instance.emit("update", _fixedDeltaTime * _timeScale);
1268
+ if (!_animated) {
1269
+ _accumulated = _deltaTime;
1270
+ }
1271
+ for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
1272
+ instance.emit("update", _deltaTime * _timeScale);
1257
1273
  instance.setvar(
1258
1274
  "ELAPSED",
1259
- instance.ELAPSED + _fixedDeltaTime * _timeScale
1275
+ instance.ELAPSED + _deltaTime * _timeScale
1260
1276
  );
1261
- _accumulated -= _fixedDeltaTime;
1262
- shouldRender = true;
1277
+ updated++;
1263
1278
  }
1264
- if (shouldRender) {
1279
+ if (updated) {
1265
1280
  instance.textalign("start", "top");
1266
1281
  instance.emit("draw");
1267
1282
  }
1268
- if (_focused && _animated) {
1269
- raf(drawFrame);
1270
- }
1271
1283
  }
1272
1284
  function setupCanvas() {
1273
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,
@@ -593,11 +593,20 @@
593
593
  textalign(align, baseline) {
594
594
  if (false) {
595
595
  assert(
596
- null == align || "string" === typeof align,
596
+ null == align || ["left", "right", "center", "start", "end"].includes(
597
+ align
598
+ ),
597
599
  "textalign: 1st param must be a string"
598
600
  );
599
601
  assert(
600
- null == baseline || "string" === typeof baseline,
602
+ null == baseline || [
603
+ "top",
604
+ "bottom",
605
+ "middle",
606
+ "hanging",
607
+ "alphabetic",
608
+ "ideographic"
609
+ ].includes(baseline),
601
610
  "textalign: 2nd param must be a string"
602
611
  );
603
612
  }
@@ -1015,7 +1024,6 @@
1015
1024
  "setvar: 1st param must be a string"
1016
1025
  );
1017
1026
  if (value == null) {
1018
- console.warn(`setvar: key "${key}" was defined as ${value}`);
1019
1027
  }
1020
1028
  }
1021
1029
  instance[key] = value;
@@ -1063,8 +1071,7 @@
1063
1071
  "setfps: 1st param must be a positive number"
1064
1072
  );
1065
1073
  }
1066
- _fixedDeltaTime = 1 / ~~value;
1067
- _accumulated = 0;
1074
+ _deltaTime = 1 / ~~value;
1068
1075
  },
1069
1076
  /**
1070
1077
  * Stops the litecanvas instance and remove all event listeners.
@@ -1074,7 +1081,8 @@
1074
1081
  for (const removeListener of _browserEventListeners) {
1075
1082
  removeListener();
1076
1083
  }
1077
- _focused = _events = false;
1084
+ cancelAnimationFrame(_rafid);
1085
+ _events = false;
1078
1086
  if (_global) {
1079
1087
  for (const key in instance) {
1080
1088
  delete root[key];
@@ -1231,38 +1239,42 @@
1231
1239
  }
1232
1240
  if (settings.pauseOnBlur) {
1233
1241
  on(root, "blur", () => {
1234
- _focused = false;
1242
+ _rafid = cancelAnimationFrame(_rafid);
1235
1243
  });
1236
1244
  on(root, "focus", () => {
1237
- _focused = true;
1238
- raf(drawFrame);
1245
+ if (!_rafid) {
1246
+ _lastFrameTime = performance.now();
1247
+ _rafid = raf(drawFrame);
1248
+ }
1239
1249
  });
1240
1250
  }
1241
1251
  instance.setfps(60);
1242
1252
  instance.emit("init", instance);
1243
1253
  _lastFrameTime = performance.now();
1244
- raf(drawFrame);
1254
+ _rafid = raf(drawFrame);
1245
1255
  }
1246
1256
  function drawFrame(now) {
1247
- let shouldRender = !_animated, frameTime = (now - _lastFrameTime) / 1e3, frameTimeMax = _fixedDeltaTime * 5;
1248
- _accumulated += frameTime > frameTimeMax ? frameTimeMax : frameTime;
1257
+ if (_animated) {
1258
+ _rafid = raf(drawFrame);
1259
+ }
1260
+ let updated = 0, frameTime = (now - _lastFrameTime) / 1e3;
1261
+ _accumulated += frameTime;
1249
1262
  _lastFrameTime = now;
1250
- while (_accumulated >= _fixedDeltaTime) {
1251
- instance.emit("update", _fixedDeltaTime * _timeScale);
1263
+ if (!_animated) {
1264
+ _accumulated = _deltaTime;
1265
+ }
1266
+ for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
1267
+ instance.emit("update", _deltaTime * _timeScale);
1252
1268
  instance.setvar(
1253
1269
  "ELAPSED",
1254
- instance.ELAPSED + _fixedDeltaTime * _timeScale
1270
+ instance.ELAPSED + _deltaTime * _timeScale
1255
1271
  );
1256
- _accumulated -= _fixedDeltaTime;
1257
- shouldRender = true;
1272
+ updated++;
1258
1273
  }
1259
- if (shouldRender) {
1274
+ if (updated) {
1260
1275
  instance.textalign("start", "top");
1261
1276
  instance.emit("draw");
1262
1277
  }
1263
- if (_focused && _animated) {
1264
- raf(drawFrame);
1265
- }
1266
1278
  }
1267
1279
  function setupCanvas() {
1268
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,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,k=0,A=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,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-w+w*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,T&&(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,w,T,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){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,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,(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){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){w=1/~~e,T=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*w;for(T+=a>l?l:a,b=e;T>=w;)A.emit("update",w*E),A.setvar("ELAPSED",A.ELAPSED+w*E),T-=w,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.1",
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} */
@@ -669,11 +669,22 @@ export default function litecanvas(settings = {}) {
669
669
  textalign(align, baseline) {
670
670
  if (DEV_BUILD) {
671
671
  assert(
672
- null == align || 'string' === typeof align,
672
+ null == align ||
673
+ ['left', 'right', 'center', 'start', 'end'].includes(
674
+ align
675
+ ),
673
676
  'textalign: 1st param must be a string'
674
677
  )
675
678
  assert(
676
- null == baseline || 'string' === typeof baseline,
679
+ null == baseline ||
680
+ [
681
+ 'top',
682
+ 'bottom',
683
+ 'middle',
684
+ 'hanging',
685
+ 'alphabetic',
686
+ 'ideographic',
687
+ ].includes(baseline),
677
688
  'textalign: 2nd param must be a string'
678
689
  )
679
690
  }
@@ -1195,8 +1206,7 @@ export default function litecanvas(settings = {}) {
1195
1206
  'setfps: 1st param must be a positive number'
1196
1207
  )
1197
1208
  }
1198
- _fixedDeltaTime = 1 / ~~value
1199
- _accumulated = 0
1209
+ _deltaTime = 1 / ~~value
1200
1210
  },
1201
1211
 
1202
1212
  /**
@@ -1207,7 +1217,8 @@ export default function litecanvas(settings = {}) {
1207
1217
  for (const removeListener of _browserEventListeners) {
1208
1218
  removeListener()
1209
1219
  }
1210
- _focused = _events = false
1220
+ cancelAnimationFrame(_rafid)
1221
+ _events = false
1211
1222
  if (_global) {
1212
1223
  for (const key in instance) {
1213
1224
  delete root[key]
@@ -1417,12 +1428,14 @@ export default function litecanvas(settings = {}) {
1417
1428
  // listen browser focus/blur events and pause the update/draw loop
1418
1429
  if (settings.pauseOnBlur) {
1419
1430
  on(root, 'blur', () => {
1420
- _focused = false
1431
+ _rafid = cancelAnimationFrame(_rafid)
1421
1432
  })
1422
1433
 
1423
1434
  on(root, 'focus', () => {
1424
- _focused = true
1425
- raf(drawFrame)
1435
+ if (!_rafid) {
1436
+ _lastFrameTime = performance.now()
1437
+ _rafid = raf(drawFrame)
1438
+ }
1426
1439
  })
1427
1440
  }
1428
1441
 
@@ -1432,37 +1445,40 @@ export default function litecanvas(settings = {}) {
1432
1445
  instance.emit('init', instance)
1433
1446
 
1434
1447
  _lastFrameTime = performance.now()
1435
- raf(drawFrame)
1448
+ _rafid = raf(drawFrame)
1436
1449
  }
1437
1450
 
1438
1451
  /**
1439
- * @param {number} now
1452
+ * @param {DOMHighResTimeStamp} now
1440
1453
  */
1441
1454
  function drawFrame(now) {
1442
- let shouldRender = !_animated,
1443
- frameTime = (now - _lastFrameTime) / 1000,
1444
- frameTimeMax = _fixedDeltaTime * 5
1455
+ if (_animated) {
1456
+ _rafid = raf(drawFrame)
1457
+ }
1458
+
1459
+ let updated = 0,
1460
+ frameTime = (now - _lastFrameTime) / 1000
1445
1461
 
1446
- _accumulated += frameTime > frameTimeMax ? frameTimeMax : frameTime
1462
+ _accumulated += frameTime
1447
1463
  _lastFrameTime = now
1448
1464
 
1449
- while (_accumulated >= _fixedDeltaTime) {
1450
- 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)
1451
1471
  instance.setvar(
1452
1472
  'ELAPSED',
1453
- instance.ELAPSED + _fixedDeltaTime * _timeScale
1473
+ instance.ELAPSED + _deltaTime * _timeScale
1454
1474
  )
1455
- _accumulated -= _fixedDeltaTime
1456
- shouldRender = true
1475
+ updated++
1457
1476
  }
1458
1477
 
1459
- if (shouldRender) {
1478
+ if (updated) {
1460
1479
  instance.textalign('start', 'top') // default values for textAlign & textBaseline
1461
1480
  instance.emit('draw')
1462
- }
1463
-
1464
- if (_focused && _animated) {
1465
- raf(drawFrame)
1481
+ console.log(updated)
1466
1482
  }
1467
1483
  }
1468
1484