litecanvas 0.74.1 → 0.74.3

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
+ _rafid = raf(drawFrame);
1252
+ }
1244
1253
  });
1245
1254
  }
1246
1255
  instance.setfps(60);
1247
1256
  instance.emit("init", instance);
1248
1257
  _lastFrameTime = performance.now();
1249
- raf(drawFrame);
1258
+ _rafid = raf(drawFrame);
1250
1259
  }
1251
1260
  function drawFrame(now) {
1252
- let shouldRender = !_animated, frameTime = (now - _lastFrameTime) / 1e3, frameTimeMax = _fixedDeltaTime * 5;
1253
- _accumulated += frameTime > frameTimeMax ? frameTimeMax : frameTime;
1261
+ if (_animated) {
1262
+ _rafid = raf(drawFrame);
1263
+ }
1264
+ let updated = 0, frameTime = (now - _lastFrameTime) / 1e3;
1254
1265
  _lastFrameTime = now;
1255
- while (_accumulated >= _fixedDeltaTime) {
1256
- instance.emit("update", _fixedDeltaTime * _timeScale);
1266
+ if (frameTime > 1) return;
1267
+ _accumulated += frameTime;
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
+ _rafid = raf(drawFrame);
1247
+ }
1239
1248
  });
1240
1249
  }
1241
1250
  instance.setfps(60);
1242
1251
  instance.emit("init", instance);
1243
1252
  _lastFrameTime = performance.now();
1244
- raf(drawFrame);
1253
+ _rafid = raf(drawFrame);
1245
1254
  }
1246
1255
  function drawFrame(now) {
1247
- let shouldRender = !_animated, frameTime = (now - _lastFrameTime) / 1e3, frameTimeMax = _fixedDeltaTime * 5;
1248
- _accumulated += frameTime > frameTimeMax ? frameTimeMax : frameTime;
1256
+ if (_animated) {
1257
+ _rafid = raf(drawFrame);
1258
+ }
1259
+ let updated = 0, frameTime = (now - _lastFrameTime) / 1e3;
1249
1260
  _lastFrameTime = now;
1250
- while (_accumulated >= _fixedDeltaTime) {
1251
- instance.emit("update", _fixedDeltaTime * _timeScale);
1261
+ if (frameTime > 1) return;
1262
+ _accumulated += frameTime;
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,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,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,u*=y/44100,p*=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>p&&(l+=u,H+=u,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=[],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=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",u.width=e),k.setvar("HEIGHT",u.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((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);k.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);k.setvar("MOUSEX",a),k.setvar("MOUSEY",l),r&&(k.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)&&k.emit("tapped",l.startX,l.startY,0),k.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);k.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);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(u,"touchend",o),s(u,"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||(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,a=(e-b)/1e3;if(b=e,!(a>1)){for(T+=a,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=u.style;n.display="block",p?(n.position="absolute",n.inset=0,k.setvar("WIDTH",u.width=t),k.setvar("HEIGHT",u.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,u.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 u="string"==typeof u?document.querySelector(u):u,k.setvar("CANVAS",u),m=u.getContext("2d"),s(u,"click",()=>l.focus()),k.WIDTH>0&&(p=!1),u.style="",u.width=k.WIDTH,u.height=k.HEIGHT||k.WIDTH,u.parentNode||document.body.appendChild(u),"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.3",
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,13 @@ 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
+ _rafid = raf(drawFrame)
1437
+ }
1426
1438
  })
1427
1439
  }
1428
1440
 
@@ -1432,38 +1444,43 @@ export default function litecanvas(settings = {}) {
1432
1444
  instance.emit('init', instance)
1433
1445
 
1434
1446
  _lastFrameTime = performance.now()
1435
- raf(drawFrame)
1447
+ _rafid = raf(drawFrame)
1436
1448
  }
1437
1449
 
1438
1450
  /**
1439
- * @param {number} now
1451
+ * @param {DOMHighResTimeStamp} now
1440
1452
  */
1441
1453
  function drawFrame(now) {
1442
- let shouldRender = !_animated,
1443
- frameTime = (now - _lastFrameTime) / 1000,
1444
- frameTimeMax = _fixedDeltaTime * 5
1454
+ if (_animated) {
1455
+ _rafid = raf(drawFrame)
1456
+ }
1457
+
1458
+ let updated = 0,
1459
+ frameTime = (now - _lastFrameTime) / 1000
1445
1460
 
1446
- _accumulated += frameTime > frameTimeMax ? frameTimeMax : frameTime
1447
1461
  _lastFrameTime = now
1448
1462
 
1449
- while (_accumulated >= _fixedDeltaTime) {
1450
- instance.emit('update', _fixedDeltaTime * _timeScale)
1463
+ if (frameTime > 1) return
1464
+
1465
+ _accumulated += frameTime
1466
+
1467
+ if (!_animated) {
1468
+ _accumulated = _deltaTime
1469
+ }
1470
+
1471
+ for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
1472
+ instance.emit('update', _deltaTime * _timeScale)
1451
1473
  instance.setvar(
1452
1474
  'ELAPSED',
1453
- instance.ELAPSED + _fixedDeltaTime * _timeScale
1475
+ instance.ELAPSED + _deltaTime * _timeScale
1454
1476
  )
1455
- _accumulated -= _fixedDeltaTime
1456
- shouldRender = true
1477
+ updated++
1457
1478
  }
1458
1479
 
1459
- if (shouldRender) {
1480
+ if (updated) {
1460
1481
  instance.textalign('start', 'top') // default values for textAlign & textBaseline
1461
1482
  instance.emit('draw')
1462
1483
  }
1463
-
1464
- if (_focused && _animated) {
1465
- raf(drawFrame)
1466
- }
1467
1484
  }
1468
1485
 
1469
1486
  function setupCanvas() {