litecanvas 0.209.0 → 0.300.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -342,8 +342,7 @@ Like `MX` and `MY`, Litecanvas also declares these other variables:
342
342
  - `H`: the height of the game canvas
343
343
  - `T`: the amount of seconds since the game started
344
344
  - `PI`: approximately 3.14 radians (or 180 degrees)
345
- - `TWO_PI`: approximately 6.28 radians (or 360 degrees)
346
- - `HALF_PI`: approximately 1.57 radians (or 90 degrees)
345
+ - `TAU`: approximately 6.28 radians (or 360 degrees)
347
346
 
348
347
  ### And much more!
349
348
 
package/dist/dist.dev.js CHANGED
@@ -115,12 +115,12 @@
115
115
  var assert = (condition, message = "Assertion failed") => {
116
116
  if (!condition) throw new Error("[Litecanvas] " + message);
117
117
  };
118
- var version = "0.209.0";
118
+ var version = "0.300.0";
119
119
  function litecanvas(settings = {}) {
120
120
  const root = window,
121
121
  math = Math,
122
122
  perf = performance,
123
- TWO_PI = math.PI * 2,
123
+ TAU = math.PI * 2,
124
124
  raf = requestAnimationFrame,
125
125
  isNumber = Number.isFinite,
126
126
  _browserEventListeners = [],
@@ -176,8 +176,7 @@
176
176
  T: 0,
177
177
  MX: -1,
178
178
  MY: -1,
179
- TWO_PI,
180
- HALF_PI: TWO_PI / 4,
179
+ TAU,
181
180
  lerp: (start, end, t) => {
182
181
  DEV: assert(isNumber(start), "lerp() 1st parameter must be a number");
183
182
  DEV: assert(isNumber(end), "lerp() 2nd parameter must be a number");
@@ -377,7 +376,7 @@
377
376
  "oval() 5th parameter must be a non-negative number",
378
377
  );
379
378
  beginPath(_ctx);
380
- _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
379
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TAU);
381
380
  instance.stroke(color);
382
381
  },
383
382
  ovalfill(x, y, radiusX, radiusY, color) {
@@ -396,7 +395,7 @@
396
395
  "ovalfill() 5th parameter must be a non-negative number",
397
396
  );
398
397
  beginPath(_ctx);
399
- _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
398
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TAU);
400
399
  instance.fill(color);
401
400
  },
402
401
  circ(x, y, radius, color) {
@@ -878,6 +877,9 @@
878
877
  );
879
878
  return internals[index];
880
879
  },
880
+ ispaused() {
881
+ return _paused;
882
+ },
881
883
  pause() {
882
884
  if (!_paused) {
883
885
  _paused = true;
@@ -896,9 +898,6 @@
896
898
  instance.emit("resumed");
897
899
  }
898
900
  },
899
- ispaused() {
900
- return _paused;
901
- },
902
901
  quit() {
903
902
  instance.emit("quit");
904
903
  instance.pause();
@@ -931,6 +930,7 @@
931
930
  }
932
931
  }
933
932
  function init() {
933
+ resizeCanvas();
934
934
  if (settings.autoscale) {
935
935
  on(root, "resize", resizeCanvas);
936
936
  }
@@ -1110,12 +1110,11 @@
1110
1110
  );
1111
1111
  _ctx = _canvas.getContext("2d");
1112
1112
  on(_canvas, "click", () => focus());
1113
- resizeCanvas();
1114
1113
  if (!_canvas.parentNode) {
1115
1114
  d.body.appendChild(_canvas);
1116
1115
  }
1117
- _canvas.style.imageRendering = "pixelated";
1118
1116
  _canvas.oncontextmenu = () => false;
1117
+ resizeCanvas();
1119
1118
  }
1120
1119
  function resizeCanvas() {
1121
1120
  DEV: assert(
@@ -1132,6 +1131,11 @@
1132
1131
  null == settings.height || (settings.width > 0 && settings.height > 0),
1133
1132
  'litecanvas() option "width" is required when the option "height" is defined',
1134
1133
  );
1134
+ DEV: assert(
1135
+ "boolean" === typeof settings.autoscale ||
1136
+ (isNumber(settings.autoscale) && settings.autoscale > 1),
1137
+ 'litecanvas() option "autoscale" must be boolean or a number > 1',
1138
+ );
1135
1139
  const width = settings.width > 0 ? settings.width : innerWidth,
1136
1140
  height =
1137
1141
  settings.width > 0 ? settings.height || settings.width : innerHeight;
@@ -1139,6 +1143,7 @@
1139
1143
  instance.def("H", height);
1140
1144
  _canvas.width = width;
1141
1145
  _canvas.height = height;
1146
+ _canvas.style = "image-rendering:pixelated";
1142
1147
  if (settings.autoscale) {
1143
1148
  let maxScale = +settings.autoscale;
1144
1149
  if (!_canvas.style.display) {
package/dist/dist.js CHANGED
@@ -116,7 +116,7 @@
116
116
  const root = window,
117
117
  math = Math,
118
118
  perf = performance,
119
- TWO_PI = math.PI * 2,
119
+ TAU = math.PI * 2,
120
120
  raf = requestAnimationFrame,
121
121
  isNumber = Number.isFinite,
122
122
  _browserEventListeners = [],
@@ -168,8 +168,7 @@
168
168
  T: 0,
169
169
  MX: -1,
170
170
  MY: -1,
171
- TWO_PI,
172
- HALF_PI: TWO_PI / 4,
171
+ TAU,
173
172
  lerp: (start, end, t) => {
174
173
  return start + t * (end - start);
175
174
  },
@@ -246,12 +245,12 @@
246
245
  },
247
246
  oval(x, y, radiusX, radiusY, color) {
248
247
  beginPath(_ctx);
249
- _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
248
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TAU);
250
249
  instance.stroke(color);
251
250
  },
252
251
  ovalfill(x, y, radiusX, radiusY, color) {
253
252
  beginPath(_ctx);
254
- _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
253
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TAU);
255
254
  instance.fill(color);
256
255
  },
257
256
  circ(x, y, radius, color) {
@@ -486,6 +485,9 @@
486
485
  ];
487
486
  return internals[index];
488
487
  },
488
+ ispaused() {
489
+ return _paused;
490
+ },
489
491
  pause() {
490
492
  if (!_paused) {
491
493
  _paused = true;
@@ -500,9 +502,6 @@
500
502
  instance.emit("resumed");
501
503
  }
502
504
  },
503
- ispaused() {
504
- return _paused;
505
- },
506
505
  quit() {
507
506
  instance.emit("quit");
508
507
  instance.pause();
@@ -532,6 +531,7 @@
532
531
  }
533
532
  }
534
533
  function init() {
534
+ resizeCanvas();
535
535
  if (settings.autoscale) {
536
536
  on(root, "resize", resizeCanvas);
537
537
  }
@@ -695,12 +695,11 @@
695
695
  _canvas = _canvas || d.createElement("canvas");
696
696
  _ctx = _canvas.getContext("2d");
697
697
  on(_canvas, "click", () => focus());
698
- resizeCanvas();
699
698
  if (!_canvas.parentNode) {
700
699
  d.body.appendChild(_canvas);
701
700
  }
702
- _canvas.style.imageRendering = "pixelated";
703
701
  _canvas.oncontextmenu = () => false;
702
+ resizeCanvas();
704
703
  }
705
704
  function resizeCanvas() {
706
705
  const width = settings.width > 0 ? settings.width : innerWidth,
@@ -710,6 +709,7 @@
710
709
  instance.def("H", height);
711
710
  _canvas.width = width;
712
711
  _canvas.height = height;
712
+ _canvas.style = "image-rendering:pixelated";
713
713
  if (settings.autoscale) {
714
714
  let maxScale = +settings.autoscale;
715
715
  if (!_canvas.style.display) {
package/dist/dist.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e=["#211e20","#555568","#a0a08b","#e9efec"];window.litecanvas=function(t={}){let a,l=window,n=Math,i=performance,o=2*n.PI,r=requestAnimationFrame,s=[],f=(e,t,a)=>{e.addEventListener(t,a,!1),s.push(()=>e.removeEventListener(t,a,!1))},d=(l.zzfxX=new AudioContext,l.zzfxV=1,(e=1,t=.05,a=220,l=0,n=0,i=.1,o=0,r=1,s=0,f=0,d=0,c=0,p=0,u=0,h=0,m=0,g=0,v=1,w=0,x=0,y=0)=>{let b=Math,z=2*b.PI,k=s*=500*z/44100/44100,E=a*=(1-t+2*t*b.random(t=[]))*z/44100,T=0,P=0,C=0,I=1,L=0,D=0,A=0,S=y<0?-1:1,H=z*S*y*2/44100,M=b.cos(H),N=b.sin,W=N(H)/4,X=1+W,q=-2*M/X,B=(1-W)/X,V=(1+S*M)/2/X,O=-(S+M)/X,R=0,F=0,G=0,Y=0;for(l=44100*l+9,w*=44100,n*=44100,i*=44100,g*=44100,f*=500*z/85766121e6,h*=z/44100,d*=z/44100,c*=44100,p=44100*p|0,e*=.3*zzfxV,S=l+w+n+i+g|0;C<S;t[C++]=A*e)++D%(100*m|0)||(A=o?1<o?2<o?3<o?N(T*T):b.max(b.min(b.tan(T),1),-1):1-(2*T/z%2+2)%2:1-4*b.abs(b.round(T/z)-T/z):N(T),A=(p?1-x+x*N(z*C/p):1)*(A<0?-1:1)*b.abs(A)**r*(C<l?C/l:C<l+w?1-(C-l)/w*(1-v):C<l+w+n?v:C<S-g?(S-C-g)/i*v:0),A=g?A/2+(g>C?0:(C<S-g?1:(S-C)/g)*t[C-g|0]/2/e):A,y&&(A=Y=V*R+O*(R=F)+V*(F=A)-B*G-q*(G=Y))),T+=(H=(a+=s+=f)*b.cos(h*P++))+H*u*N(C**5),I&&++I>c&&(a+=d,E+=d,I=0),!p||++L%p||(a=E,s=k,I=I||1);(e=zzfxX.createBuffer(1,S,44100)).getChannelData(0).set(t),(a=zzfxX.createBufferSource()).buffer=e,a.connect(zzfxX.destination),a.start()}),c=(t=Object.assign({width:null,height:null,autoscale:!0,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0},t)).loop,p=!1,u,h,m=1,g,v=.5,w=1,x,y=1e3/60,b,z=0,k=3,E="sans-serif",T=20,P=1.2,C=Date.now(),I=e,L=[],D=[.5,0,1750,,,.3,1,,,,600,.1],A={},S={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:o,HALF_PI:o/4,lerp:(e,t,a)=>e+a*(t-e),deg2rad:e=>n.PI/180*e,rad2deg:e=>180/n.PI*e,mod:(e,t)=>(e%t+t)%t||0,round:(e,t=0)=>{if(!t)return n.round(e);let a=10**t;return n.round(e*a)/a},clamp:(e,t,a)=>e<t?t:e>a?a:e,dist:(e,t,a,l)=>n.hypot(a-e,l-t),wrap:(e,t,a)=>e-(a-t)*n.floor((e-t)/(a-t)),map(e,t,a,l,n,i){let o=(e-t)/(a-t)*(n-l)+l;return i?S.clamp(o,l,n):o},norm:(e,t,a)=>S.map(e,t,a,0,1),rand:(e=0,t=1)=>(C=(1664525*C+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>~~S.rand(e,t+1),rseed(e){C=~~e},cls(e){null==e?g.clearRect(0,0,S.W,S.H):S.rectfill(0,0,S.W,S.H,e)},rect(e,t,a,l,n,i){g.beginPath(),g[i?"roundRect":"rect"](~~e-v,~~t-v,~~a+2*v,~~l+2*v,i),S.stroke(n)},rectfill(e,t,a,l,n,i){g.beginPath(),g[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),S.fill(n)},oval(e,t,a,l,n){g.beginPath(),g.ellipse(~~e,~~t,~~a,~~l,0,0,o),S.stroke(n)},ovalfill(e,t,a,l,n){g.beginPath(),g.ellipse(~~e,~~t,~~a,~~l,0,0,o),S.fill(n)},circ(e,t,a,l){S.oval(e,t,a,a,l)},circfill(e,t,a,l){S.ovalfill(e,t,a,a,l)},shape(e){g.beginPath();for(let t=0;t<e.length;t+=2)t?g.lineTo(~~e[t],~~e[t+1]):g.moveTo(~~e[t],~~e[t+1]);g.lineTo(~~e[0],~~e[1])},line(e,t,a,l,n){g.beginPath();let i=v&&~~e==~~a?.5:0,o=v&&~~t==~~l?.5:0;g.moveTo(~~e+i,~~t+o),g.lineTo(~~a+i,~~l+o),S.stroke(n)},linewidth(e){g.lineWidth=~~e,v=~~e%2?.5:0},linedash(e,t=0){g.setLineDash(e),g.lineDashOffset=t},text(e,t,a,l=k,n="normal"){g.font=`${n} ${T}px ${E}`,g.fillStyle=X(l);let i=(""+a).split("\n");for(let a=0;a<i.length;a++)g.fillText(i[a],~~e,~~t+T*P*a)},textgap(e){P=e},textfont(e){E=e},textsize(e){T=e},textalign(e,t){e&&(g.textAlign=e),t&&(g.textBaseline=t)},image(e,t,a){g.drawImage(a,~~e,~~t)},spr(e,t,a){let l=a.replace(/[^\w.\n]/g,"").split("\n").filter(e=>e);for(let a=0;a<l.length;a++)for(let n=0;n<l[a].length;n++)"."!==l[a][n]&&S.rectfill(e+n,t+a,1,1,parseInt(l[a][n],36)||0)},paint(e,t,a,l={}){let n=l.canvas||new OffscreenCanvas(1,1),i=l.scale||1,o=g;return n.width=e*i,n.height=t*i,(g=n.getContext("2d")).scale(i,i),a(g),g=o,n.transferToImageBitmap()},ctx:e=>(e&&(g=e),g),push(e=0,t=e,a=0,l=1,n=l){g.save(),S.translate(e,t),S.rotate(a),S.scale(l,n)},pop(){g.restore()},translate(e,t){g.translate(~~e,~~t)},scale(e,t=e){g.scale(e,t)},rotate(e){g.rotate(e)},alpha(e){g.globalAlpha=S.clamp(e,0,1)},fill(e){g.fillStyle=X(e),g.fill()},stroke(e){g.strokeStyle=X(e),g.stroke()},clip(e){g.beginPath(),e(g),g.clip()},sfx:(e,t,a)=>!!l.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e||=D,(t||a>=0)&&((e=e.slice())[0]=a*(e[0]||1),e[10]=~~e[10]+t),d.apply(0,e),e),volume(e){l.zzfxV=e},canvas:()=>h,use(e,t={}){var a=e,l=t;let n=a(S,l);for(let e in n)S.def(e,n[e])},listen:(e,t)=>{A[e=e.toLowerCase()]=A[e]||new Set,A[e].add(t)},unlisten:(e,t)=>{A[e=e.toLowerCase()]&&A[e].delete(t)},emit:(e,t,a,n,i)=>(p&&(W("before:"+(e=e.toLowerCase()),t,a,n,i),c||l[e]===S[e]||"function"!=typeof l[e]||l[e](t,a,n,i),W(e,t,a,n,i),W("after:"+e,t,a,n,i)),t),pal(t,a=3){I=t||e,L=[],k=a,S.emit("pal",I,k)},palc(e,t){null==e?L=[]:L[e]=t},def(e,a){S[e]=a,t.global&&(l[e]=a)},timescale(e){w=e},framerate(e){y=1e3/~~e},stat:e=>[t,p,y/1e3,m,A,I,D,w,l.zzfxV,C,T,E,L,P][e],pause(){u||(u=!0,z=~~cancelAnimationFrame(z),S.emit("paused"))},resume(){p&&u&&(H(),u=!1,S.emit("resumed"))},ispaused:()=>u,quit(){for(let e of(S.emit("quit"),S.pause(),p=!1,A={},s))e();if(t.global){for(let e in S)delete l[e];delete l.ENGINE}}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))S[e]=n[e];function H(){z||(b=0,x=i.now(),z=r(M))}function M(){z=r(M);let e=i.now(),t=0,a=e-x;for(x=e,b+=a<100?a:y;b>=y;){t++,b-=y;let e=y/1e3*w;S.emit("update",e,t),S.def("T",S.T+e)}t&&(S.emit("draw",g),t>1&&(b=0))}function N(){let e=t.width>0?t.width:innerWidth,a=t.width>0?t.height||t.width:innerHeight;if(S.def("W",e),S.def("H",a),h.width=e,h.height=a,t.autoscale){let l=+t.autoscale;h.style.display||(h.style.display="block",h.style.margin="auto"),m=n.min(innerWidth/e,innerHeight/a),m=l>1&&m>l?l:m,h.style.width=e*m+"px",h.style.height=a*m+"px"}g.imageSmoothingEnabled=!1,S.textalign("start","top"),S.emit("resized",m)}function W(e,t,a,l,n){if(A[e])for(let i of A[e])i(t,a,l,n)}function X(e){return I[~~(L[e]??e)%I.length]}if(t.global){if(l.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(l,S),l.ENGINE=S}if(a=document,g=(h=(h="string"==typeof t.canvas?a.querySelector(t.canvas):t.canvas)||a.createElement("canvas")).getContext("2d"),f(h,"click",()=>focus()),N(),h.parentNode||a.body.appendChild(h),h.style.imageRendering="pixelated",h.oncontextmenu=()=>!1,c)for(let e in c)c[e]&&S.listen(e,c[e]);return r(function(){if(t.autoscale&&f(l,"resize",N),t.tapEvents){let e=e=>[(e.pageX-h.offsetLeft)/m,(e.pageY-h.offsetTop)/m],t=new Map,a=(e,a,l)=>{let n={x:a,y:l,xi:a,yi:l,t:i.now()};return t.set(e,n),n},n=(e,l,n)=>{let i=t.get(e)||a(e);i.x=l,i.y=n},o=e=>e&&i.now()-e.t<=300,r=!1;f(h,"mousedown",t=>{if(!t.button){t.preventDefault();let[l,n]=e(t);S.emit("tap",l,n,0),a(0,l,n),r=!0}}),f(h,"mouseup",a=>{if(!a.button){a.preventDefault();let l=t.get(0),[n,i]=e(a);o(l)&&S.emit("tapped",l.xi,l.yi,0),S.emit("untap",n,i,0),t.delete(0),r=!1}}),f(l,"mousemove",t=>{t.preventDefault();let[a,l]=e(t);S.def("MX",a),S.def("MY",l),r&&(S.emit("tapping",a,l,0),n(0,a,l))}),f(h,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l);S.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),f(h,"touchmove",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,l]=e(a);S.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let s=e=>{e.preventDefault();let a=[];for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,l]of t)a.includes(e)||(o(l)&&S.emit("tapped",l.xi,l.yi,e),S.emit("untap",l.x,l.y,e),t.delete(e))};f(h,"touchend",s),f(h,"touchcancel",s),f(l,"blur",()=>{for(let[e,a]of(r=!1,t))S.emit("untap",a.x,a.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,a=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0,n="";f(l,"keydown",a=>{let l=a.key.toLowerCase();e.has(l)||(e.add(l),t.add(l),n=" "===l?"space":l)}),f(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),f(l,"blur",()=>e.clear()),S.listen("after:update",()=>t.clear()),S.def("iskeydown",t=>a(e,t)),S.def("iskeypressed",e=>a(t,e)),S.def("lastkey",()=>n)}p=!0,S.emit("init",S),u||H()}),S}})();
1
+ (()=>{var e=["#211e20","#555568","#a0a08b","#e9efec"];window.litecanvas=function(t={}){let a,l=window,n=Math,i=performance,o=2*n.PI,r=requestAnimationFrame,s=[],f=(e,t,a)=>{e.addEventListener(t,a,!1),s.push(()=>e.removeEventListener(t,a,!1))},d=(l.zzfxX=new AudioContext,l.zzfxV=1,(e=1,t=.05,a=220,l=0,n=0,i=.1,o=0,r=1,s=0,f=0,d=0,c=0,p=0,u=0,h=0,m=0,g=0,v=1,w=0,x=0,y=0)=>{let b=Math,z=2*b.PI,k=s*=500*z/44100/44100,E=a*=(1-t+2*t*b.random(t=[]))*z/44100,T=0,C=0,P=0,I=1,D=0,L=0,S=0,A=y<0?-1:1,M=z*A*y*2/44100,N=b.cos(M),W=b.sin,X=W(M)/4,H=1+X,q=-2*N/H,B=(1-X)/H,V=(1+A*N)/2/H,O=-(A+N)/H,G=0,R=0,Y=0,$=0;for(l=44100*l+9,w*=44100,n*=44100,i*=44100,g*=44100,f*=500*z/85766121e6,h*=z/44100,d*=z/44100,c*=44100,p=44100*p|0,e*=.3*zzfxV,A=l+w+n+i+g|0;P<A;t[P++]=S*e)++L%(100*m|0)||(S=o?1<o?2<o?3<o?W(T*T):b.max(b.min(b.tan(T),1),-1):1-(2*T/z%2+2)%2:1-4*b.abs(b.round(T/z)-T/z):W(T),S=(p?1-x+x*W(z*P/p):1)*(S<0?-1:1)*b.abs(S)**r*(P<l?P/l:P<l+w?1-(P-l)/w*(1-v):P<l+w+n?v:P<A-g?(A-P-g)/i*v:0),S=g?S/2+(g>P?0:(P<A-g?1:(A-P)/g)*t[P-g|0]/2/e):S,y&&(S=$=V*G+O*(G=R)+V*(R=S)-B*Y-q*(Y=$))),T+=(M=(a+=s+=f)*b.cos(h*C++))+M*u*W(P**5),I&&++I>c&&(a+=d,E+=d,I=0),!p||++D%p||(a=E,s=k,I=I||1);(e=zzfxX.createBuffer(1,A,44100)).getChannelData(0).set(t),(a=zzfxX.createBufferSource()).buffer=e,a.connect(zzfxX.destination),a.start()}),c=(t=Object.assign({width:null,height:null,autoscale:!0,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0},t)).loop,p=!1,u,h,m=1,g,v=.5,w=1,x,y=1e3/60,b,z=0,k=3,E="sans-serif",T=20,C=1.2,P=Date.now(),I=e,D=[],L=[.5,0,1750,,,.3,1,,,,600,.1],S={},A={W:0,H:0,T:0,MX:-1,MY:-1,TAU:o,lerp:(e,t,a)=>e+a*(t-e),deg2rad:e=>n.PI/180*e,rad2deg:e=>180/n.PI*e,mod:(e,t)=>(e%t+t)%t||0,round:(e,t=0)=>{if(!t)return n.round(e);let a=10**t;return n.round(e*a)/a},clamp:(e,t,a)=>e<t?t:e>a?a:e,dist:(e,t,a,l)=>n.hypot(a-e,l-t),wrap:(e,t,a)=>e-(a-t)*n.floor((e-t)/(a-t)),map(e,t,a,l,n,i){let o=(e-t)/(a-t)*(n-l)+l;return i?A.clamp(o,l,n):o},norm:(e,t,a)=>A.map(e,t,a,0,1),rand:(e=0,t=1)=>(P=(1664525*P+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>~~A.rand(e,t+1),rseed(e){P=~~e},cls(e){null==e?g.clearRect(0,0,A.W,A.H):A.rectfill(0,0,A.W,A.H,e)},rect(e,t,a,l,n,i){g.beginPath(),g[i?"roundRect":"rect"](~~e-v,~~t-v,~~a+2*v,~~l+2*v,i),A.stroke(n)},rectfill(e,t,a,l,n,i){g.beginPath(),g[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),A.fill(n)},oval(e,t,a,l,n){g.beginPath(),g.ellipse(~~e,~~t,~~a,~~l,0,0,o),A.stroke(n)},ovalfill(e,t,a,l,n){g.beginPath(),g.ellipse(~~e,~~t,~~a,~~l,0,0,o),A.fill(n)},circ(e,t,a,l){A.oval(e,t,a,a,l)},circfill(e,t,a,l){A.ovalfill(e,t,a,a,l)},shape(e){g.beginPath();for(let t=0;t<e.length;t+=2)t?g.lineTo(~~e[t],~~e[t+1]):g.moveTo(~~e[t],~~e[t+1]);g.lineTo(~~e[0],~~e[1])},line(e,t,a,l,n){g.beginPath();let i=v&&~~e==~~a?.5:0,o=v&&~~t==~~l?.5:0;g.moveTo(~~e+i,~~t+o),g.lineTo(~~a+i,~~l+o),A.stroke(n)},linewidth(e){g.lineWidth=~~e,v=~~e%2?.5:0},linedash(e,t=0){g.setLineDash(e),g.lineDashOffset=t},text(e,t,a,l=k,n="normal"){g.font=`${n} ${T}px ${E}`,g.fillStyle=H(l);let i=(""+a).split("\n");for(let a=0;a<i.length;a++)g.fillText(i[a],~~e,~~t+T*C*a)},textgap(e){C=e},textfont(e){E=e},textsize(e){T=e},textalign(e,t){e&&(g.textAlign=e),t&&(g.textBaseline=t)},image(e,t,a){g.drawImage(a,~~e,~~t)},spr(e,t,a){let l=a.replace(/[^\w.\n]/g,"").split("\n").filter(e=>e);for(let a=0;a<l.length;a++)for(let n=0;n<l[a].length;n++)"."!==l[a][n]&&A.rectfill(e+n,t+a,1,1,parseInt(l[a][n],36)||0)},paint(e,t,a,l={}){let n=l.canvas||new OffscreenCanvas(1,1),i=l.scale||1,o=g;return n.width=e*i,n.height=t*i,(g=n.getContext("2d")).scale(i,i),a(g),g=o,n.transferToImageBitmap()},ctx:e=>(e&&(g=e),g),push(e=0,t=e,a=0,l=1,n=l){g.save(),A.translate(e,t),A.rotate(a),A.scale(l,n)},pop(){g.restore()},translate(e,t){g.translate(~~e,~~t)},scale(e,t=e){g.scale(e,t)},rotate(e){g.rotate(e)},alpha(e){g.globalAlpha=A.clamp(e,0,1)},fill(e){g.fillStyle=H(e),g.fill()},stroke(e){g.strokeStyle=H(e),g.stroke()},clip(e){g.beginPath(),e(g),g.clip()},sfx:(e,t,a)=>!!l.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e||=L,(t||a>=0)&&((e=e.slice())[0]=a*(e[0]||1),e[10]=~~e[10]+t),d.apply(0,e),e),volume(e){l.zzfxV=e},canvas:()=>h,use(e,t={}){var a=e,l=t;let n=a(A,l);for(let e in n)A.def(e,n[e])},listen:(e,t)=>{S[e=e.toLowerCase()]=S[e]||new Set,S[e].add(t)},unlisten:(e,t)=>{S[e=e.toLowerCase()]&&S[e].delete(t)},emit:(e,t,a,n,i)=>(p&&(X("before:"+(e=e.toLowerCase()),t,a,n,i),c||l[e]===A[e]||"function"!=typeof l[e]||l[e](t,a,n,i),X(e,t,a,n,i),X("after:"+e,t,a,n,i)),t),pal(t,a=3){I=t||e,D=[],k=a,A.emit("pal",I,k)},palc(e,t){null==e?D=[]:D[e]=t},def(e,a){A[e]=a,t.global&&(l[e]=a)},timescale(e){w=e},framerate(e){y=1e3/~~e},stat:e=>[t,p,y/1e3,m,S,I,L,w,l.zzfxV,P,T,E,D,C][e],ispaused:()=>u,pause(){u||(u=!0,z=~~cancelAnimationFrame(z),A.emit("paused"))},resume(){p&&u&&(M(),u=!1,A.emit("resumed"))},quit(){for(let e of(A.emit("quit"),A.pause(),p=!1,S={},s))e();if(t.global){for(let e in A)delete l[e];delete l.ENGINE}}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))A[e]=n[e];function M(){z||(b=0,x=i.now(),z=r(N))}function N(){z=r(N);let e=i.now(),t=0,a=e-x;for(x=e,b+=a<100?a:y;b>=y;){t++,b-=y;let e=y/1e3*w;A.emit("update",e,t),A.def("T",A.T+e)}t&&(A.emit("draw",g),t>1&&(b=0))}function W(){let e=t.width>0?t.width:innerWidth,a=t.width>0?t.height||t.width:innerHeight;if(A.def("W",e),A.def("H",a),h.width=e,h.height=a,h.style="image-rendering:pixelated",t.autoscale){let l=+t.autoscale;h.style.display||(h.style.display="block",h.style.margin="auto"),m=n.min(innerWidth/e,innerHeight/a),m=l>1&&m>l?l:m,h.style.width=e*m+"px",h.style.height=a*m+"px"}g.imageSmoothingEnabled=!1,A.textalign("start","top"),A.emit("resized",m)}function X(e,t,a,l,n){if(S[e])for(let i of S[e])i(t,a,l,n)}function H(e){return I[~~(D[e]??e)%I.length]}if(t.global){if(l.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(l,A),l.ENGINE=A}if(a=document,g=(h=(h="string"==typeof t.canvas?a.querySelector(t.canvas):t.canvas)||a.createElement("canvas")).getContext("2d"),f(h,"click",()=>focus()),h.parentNode||a.body.appendChild(h),h.oncontextmenu=()=>!1,W(),c)for(let e in c)c[e]&&A.listen(e,c[e]);return r(function(){if(W(),t.autoscale&&f(l,"resize",W),t.tapEvents){let e=e=>[(e.pageX-h.offsetLeft)/m,(e.pageY-h.offsetTop)/m],t=new Map,a=(e,a,l)=>{let n={x:a,y:l,xi:a,yi:l,t:i.now()};return t.set(e,n),n},n=(e,l,n)=>{let i=t.get(e)||a(e);i.x=l,i.y=n},o=e=>e&&i.now()-e.t<=300,r=!1;f(h,"mousedown",t=>{if(!t.button){t.preventDefault();let[l,n]=e(t);A.emit("tap",l,n,0),a(0,l,n),r=!0}}),f(h,"mouseup",a=>{if(!a.button){a.preventDefault();let l=t.get(0),[n,i]=e(a);o(l)&&A.emit("tapped",l.xi,l.yi,0),A.emit("untap",n,i,0),t.delete(0),r=!1}}),f(l,"mousemove",t=>{t.preventDefault();let[a,l]=e(t);A.def("MX",a),A.def("MY",l),r&&(A.emit("tapping",a,l,0),n(0,a,l))}),f(h,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l);A.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),f(h,"touchmove",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,l]=e(a);A.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let s=e=>{e.preventDefault();let a=[];for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,l]of t)a.includes(e)||(o(l)&&A.emit("tapped",l.xi,l.yi,e),A.emit("untap",l.x,l.y,e),t.delete(e))};f(h,"touchend",s),f(h,"touchcancel",s),f(l,"blur",()=>{for(let[e,a]of(r=!1,t))A.emit("untap",a.x,a.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,a=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0,n="";f(l,"keydown",a=>{let l=a.key.toLowerCase();e.has(l)||(e.add(l),t.add(l),n=" "===l?"space":l)}),f(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),f(l,"blur",()=>e.clear()),A.listen("after:update",()=>t.clear()),A.def("iskeydown",t=>a(e,t)),A.def("iskeypressed",e=>a(t,e)),A.def("lastkey",()=>n)}p=!0,A.emit("init",A),u||M()}),A}})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.209.0",
3
+ "version": "0.300.0",
4
4
  "description": "Lightweight HTML5 canvas 2D game engine suitable for small projects and creative coding. Inspired by PICO-8 and p5.js/Processing.",
5
5
  "license": "MIT",
6
6
  "author": "Luiz Bills <luizbills@pm.me>",
@@ -34,13 +34,13 @@
34
34
  "devDependencies": {
35
35
  "@happy-dom/global-registrator": "^20.9.0",
36
36
  "@size-limit/preset-small-lib": "^12.1.0",
37
- "@swc/core": "^1.15.33",
38
- "ava": "^7.0.0",
37
+ "@swc/core": "^1.15.40",
38
+ "ava": "^8.0.1",
39
39
  "esbuild": "^0.28.0",
40
40
  "genversion": "^3.2.0",
41
41
  "gzip-size": "^7.0.0",
42
42
  "prettier": "^3.8.3",
43
- "sinon": "^21.1.2",
43
+ "sinon": "^22.0.0",
44
44
  "size-limit": "^12.1.0",
45
45
  "tap-min": "^3.0.0"
46
46
  },
package/src/index.js CHANGED
@@ -14,7 +14,7 @@ export default function litecanvas(settings = {}) {
14
14
  const root = window,
15
15
  math = Math,
16
16
  perf = performance,
17
- TWO_PI = math.PI * 2,
17
+ TAU = math.PI * 2,
18
18
  raf = requestAnimationFrame,
19
19
  isNumber = Number.isFinite,
20
20
  /** @type {Function[]} */
@@ -117,20 +117,9 @@ export default function litecanvas(settings = {}) {
117
117
  * Twice the value of the mathematical constant PI (π).
118
118
  * Approximately 6.28318
119
119
  *
120
- * Note: TWO_PI radians equals 360°, PI radians equals 180°,
121
- * HALF_PI radians equals 90°, and HALF_PI/2 radians equals 45°.
122
- *
123
120
  * @type {number}
124
121
  */
125
- TWO_PI,
126
-
127
- /**
128
- * Half the value of the mathematical constant PI (π).
129
- * Approximately 1.57079
130
- *
131
- * @type {number}
132
- */
133
- HALF_PI: TWO_PI / 4,
122
+ TAU,
134
123
 
135
124
  /**
136
125
  * Calculates a linear (interpolation) value over t%.
@@ -181,9 +170,6 @@ export default function litecanvas(settings = {}) {
181
170
  * @param {number} a dividend
182
171
  * @param {number} b divisor
183
172
  * @returns {number} the remainder
184
- * @example
185
- * mod(-1, 5) // => 4
186
- * -1 % 5 // => -1
187
173
  */
188
174
  mod(a, b) {
189
175
  DEV: assert(isNumber(a), 'mod() 1st parameter must be a number')
@@ -499,7 +485,7 @@ export default function litecanvas(settings = {}) {
499
485
 
500
486
  beginPath(_ctx)
501
487
 
502
- _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI)
488
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TAU)
503
489
  instance.stroke(color)
504
490
  },
505
491
 
@@ -530,7 +516,7 @@ export default function litecanvas(settings = {}) {
530
516
 
531
517
  beginPath(_ctx)
532
518
 
533
- _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI)
519
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TAU)
534
520
  instance.fill(color)
535
521
  },
536
522
 
@@ -1336,6 +1322,15 @@ export default function litecanvas(settings = {}) {
1336
1322
  return internals[index]
1337
1323
  },
1338
1324
 
1325
+ /**
1326
+ * Returns `true` if the engine loop is paused.
1327
+ *
1328
+ * @returns {boolean}
1329
+ */
1330
+ ispaused() {
1331
+ return _paused
1332
+ },
1333
+
1339
1334
  /**
1340
1335
  * Pauses the engine loop (update & draw).
1341
1336
  */
@@ -1363,15 +1358,6 @@ export default function litecanvas(settings = {}) {
1363
1358
  }
1364
1359
  },
1365
1360
 
1366
- /**
1367
- * Returns `true` if the engine loop is paused.
1368
- *
1369
- * @returns {boolean}
1370
- */
1371
- ispaused() {
1372
- return _paused
1373
- },
1374
-
1375
1361
  /**
1376
1362
  * Shutdown the litecanvas instance and remove all event listeners.
1377
1363
  */
@@ -1421,6 +1407,8 @@ export default function litecanvas(settings = {}) {
1421
1407
  }
1422
1408
 
1423
1409
  function init() {
1410
+ resizeCanvas()
1411
+
1424
1412
  // listen window resize event when "autoscale" is enabled
1425
1413
  if (settings.autoscale) {
1426
1414
  on(root, 'resize', resizeCanvas)
@@ -1748,16 +1736,14 @@ export default function litecanvas(settings = {}) {
1748
1736
 
1749
1737
  on(_canvas, 'click', () => focus())
1750
1738
 
1751
- resizeCanvas()
1752
-
1753
1739
  if (!_canvas.parentNode) {
1754
1740
  d.body.appendChild(_canvas)
1755
1741
  }
1756
1742
 
1757
- _canvas.style.imageRendering = 'pixelated'
1758
-
1759
1743
  // disable default browser's right click in canvas
1760
1744
  _canvas.oncontextmenu = () => false
1745
+
1746
+ resizeCanvas()
1761
1747
  }
1762
1748
 
1763
1749
  function resizeCanvas() {
@@ -1774,6 +1760,11 @@ export default function litecanvas(settings = {}) {
1774
1760
 
1775
1761
  'litecanvas() option "width" is required when the option "height" is defined'
1776
1762
  )
1763
+ DEV: assert(
1764
+ 'boolean' === typeof settings.autoscale ||
1765
+ (isNumber(settings.autoscale) && settings.autoscale > 1),
1766
+ 'litecanvas() option "autoscale" must be boolean or a number > 1'
1767
+ )
1777
1768
 
1778
1769
  const width = settings.width > 0 ? settings.width : innerWidth,
1779
1770
  height = settings.width > 0 ? settings.height || settings.width : innerHeight
@@ -1784,6 +1775,9 @@ export default function litecanvas(settings = {}) {
1784
1775
  _canvas.width = width
1785
1776
  _canvas.height = height
1786
1777
 
1778
+ /** @ts-ignore */
1779
+ _canvas.style = 'image-rendering:pixelated'
1780
+
1787
1781
  if (settings.autoscale) {
1788
1782
  let maxScale = +settings.autoscale
1789
1783
  if (!_canvas.style.display) {
package/src/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '0.209.0'
2
+ export const version = '0.300.0'
package/types/global.d.ts CHANGED
@@ -25,16 +25,8 @@ declare global {
25
25
  /**
26
26
  * Twice the value of the mathematical constant PI (π).
27
27
  * Approximately 6.28318
28
- *
29
- * Note: TWO_PI radians equals 360°, PI radians equals 180°,
30
- * HALF_PI radians equals 90°, and HALF_PI/2 radians equals 45°.
31
- */
32
- var TWO_PI: number
33
- /**
34
- * Half the value of the mathematical constant PI (π).
35
- * Approximately 1.57079
36
28
  */
37
- var HALF_PI: number
29
+ var TAU: number
38
30
  /**
39
31
  * Calculates a linear (interpolation) value over t%.
40
32
  *
@@ -68,8 +60,8 @@ declare global {
68
60
  * @param b divisor
69
61
  * @returns the remainder
70
62
  * @example
71
- * mod(-1, 5) // => 4
72
- * -1 % 5 // => -1
63
+ * mod(-1, 5) // => 4
64
+ * -1 % 5 // => -1
73
65
  */
74
66
  function mod(a: number, b: number): number
75
67
  /**
package/types/types.d.ts CHANGED
@@ -19,16 +19,8 @@ type LitecanvasInstance = {
19
19
  /**
20
20
  * Twice the value of the mathematical constant PI (π).
21
21
  * Approximately 6.28318
22
- *
23
- * Note: TWO_PI radians equals 360°, PI radians equals 180°,
24
- * HALF_PI radians equals 90°, and HALF_PI/2 radians equals 45°.
25
- */
26
- TWO_PI: number
27
- /**
28
- * Half the value of the mathematical constant PI (π).
29
- * Approximately 1.57079
30
22
  */
31
- HALF_PI: number
23
+ TAU: number
32
24
  /**
33
25
  * Calculates a linear (interpolation) value over t%.
34
26
  *
@@ -62,8 +54,8 @@ type LitecanvasInstance = {
62
54
  * @param b divisor
63
55
  * @returns the remainder
64
56
  * @example
65
- * mod(-1, 5) // => 4
66
- * -1 % 5 // => -1
57
+ * mod(-1, 5) // => 4
58
+ * -1 % 5 // => -1
67
59
  */
68
60
  mod(a: number, b: number): number
69
61
  /**