litecanvas 0.75.1 → 0.77.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
@@ -32,7 +32,7 @@ npm install
32
32
  npm run dev
33
33
  ```
34
34
 
35
- If you prefer, you can manually install the package via NPM:
35
+ If you prefer, you can manually install via [NPM](https://www.npmjs.com/package/litecanvas):
36
36
 
37
37
  ```
38
38
  npm install litecanvas
package/dist/dist.dev.js CHANGED
@@ -36,7 +36,6 @@
36
36
  () => elem.removeEventListener(evt, callback, false)
37
37
  );
38
38
  }, isFinite = Number.isFinite, defaults = {
39
- fullscreen: true,
40
39
  width: null,
41
40
  height: null,
42
41
  autoscale: true,
@@ -51,7 +50,7 @@
51
50
  animate: true
52
51
  };
53
52
  settings = Object.assign(defaults, settings);
54
- 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 = {
53
+ let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _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 = {
55
54
  init: null,
56
55
  update: null,
57
56
  draw: null,
@@ -894,9 +893,11 @@
894
893
  "string" === typeof eventName,
895
894
  "emit: 1st param must be a string"
896
895
  );
897
- triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
898
- triggerEvent(eventName, arg1, arg2, arg3, arg4);
899
- triggerEvent("after:" + eventName, arg1, arg2, arg3, arg4);
896
+ if (_initialized) {
897
+ triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
898
+ triggerEvent(eventName, arg1, arg2, arg3, arg4);
899
+ triggerEvent("after:" + eventName, arg1, arg2, arg3, arg4);
900
+ }
900
901
  },
901
902
  /**
902
903
  * Get a color by index
@@ -937,11 +938,19 @@
937
938
  * @param {number} height
938
939
  */
939
940
  resize(width, height) {
940
- DEV: assert(isFinite(width), "resize: 1st param must be a number");
941
- DEV: assert(isFinite(height), "resize: 2nd param must be a number");
941
+ DEV: assert(
942
+ isFinite(width) && width > 0,
943
+ "resize: 1st param must be a number"
944
+ );
945
+ DEV: assert(
946
+ isFinite(height) && height > 0,
947
+ "resize: 2nd param must be a number"
948
+ );
942
949
  instance.setvar("WIDTH", _canvas.width = width);
943
950
  instance.setvar("HEIGHT", _canvas.height = height);
944
- pageResized();
951
+ instance.setvar("CENTERX", instance.WIDTH / 2);
952
+ instance.setvar("CENTERY", instance.HEIGHT / 2);
953
+ onResize();
945
954
  },
946
955
  /**
947
956
  * The scale of the game's delta time (dt).
@@ -999,10 +1008,9 @@
999
1008
  for (const [callback, config] of _plugins) {
1000
1009
  loadPlugin(callback, config);
1001
1010
  }
1002
- if (_fullscreen || _autoscale) {
1003
- on(root, "resize", pageResized);
1011
+ if (_autoscale) {
1012
+ on(root, "resize", onResize);
1004
1013
  }
1005
- pageResized();
1006
1014
  if (settings.tapEvents) {
1007
1015
  const _getXY = (pageX, pageY) => [
1008
1016
  (pageX - _canvas.offsetLeft) / _scale,
@@ -1101,22 +1109,23 @@
1101
1109
  });
1102
1110
  }
1103
1111
  if (settings.keyboardEvents) {
1104
- const _keys = /* @__PURE__ */ new Set();
1112
+ const _keyDownList = /* @__PURE__ */ new Set();
1105
1113
  const iskeydown = (key) => {
1106
1114
  DEV: assert(
1107
1115
  "string" === typeof key,
1108
1116
  "iskeydown: 1st param must be a string"
1109
1117
  );
1110
- return "any" === key ? _keys.size > 0 : _keys.has(key.toLowerCase());
1118
+ key = key.toLowerCase();
1119
+ return "any" === key ? _keyDownList.size > 0 : _keyDownList.has("space" === key ? " " : key);
1111
1120
  };
1112
1121
  instance.setvar("iskeydown", iskeydown);
1113
1122
  on(root, "keydown", (event) => {
1114
- _keys.add(event.key.toLowerCase());
1123
+ _keyDownList.add(event.key.toLowerCase());
1115
1124
  });
1116
1125
  on(root, "keyup", (event) => {
1117
- _keys.delete(event.key.toLowerCase());
1126
+ _keyDownList.delete(event.key.toLowerCase());
1118
1127
  });
1119
- on(root, "blur", () => _keys.clear());
1128
+ on(root, "blur", () => _keyDownList.clear());
1120
1129
  }
1121
1130
  if (settings.pauseOnBlur) {
1122
1131
  on(root, "blur", () => {
@@ -1139,21 +1148,23 @@
1139
1148
  }
1140
1149
  let updated = 0, frameTime = (now - _lastFrameTime) / 1e3;
1141
1150
  _lastFrameTime = now;
1142
- if (frameTime > _deltaTime * 30)
1143
- return console.log("skipping too long frame");
1144
- _accumulated += frameTime;
1145
- if (!_animated) {
1146
- _accumulated = _deltaTime;
1147
- }
1148
- for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
1149
- instance.emit("update", _deltaTime * _timeScale);
1150
- instance.setvar(
1151
- "ELAPSED",
1152
- instance.ELAPSED + _deltaTime * _timeScale
1153
- );
1154
- updated++;
1151
+ if (frameTime > _deltaTime * 30) {
1152
+ console.log("skipping too long frame");
1153
+ } else {
1154
+ _accumulated += frameTime;
1155
+ if (!_animated) {
1156
+ _accumulated = _deltaTime;
1157
+ }
1158
+ for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
1159
+ instance.emit("update", _deltaTime * _timeScale);
1160
+ instance.setvar(
1161
+ "ELAPSED",
1162
+ instance.ELAPSED + _deltaTime * _timeScale
1163
+ );
1164
+ updated++;
1165
+ }
1155
1166
  }
1156
- if (updated) {
1167
+ if (updated || !_animated) {
1157
1168
  instance.textalign("start", "top");
1158
1169
  instance.emit("draw");
1159
1170
  }
@@ -1165,44 +1176,43 @@
1165
1176
  "Invalid canvas element"
1166
1177
  );
1167
1178
  DEV: assert(
1168
- null === instance.WIDTH || instance.WIDTH > 0,
1179
+ null == instance.WIDTH || instance.WIDTH > 0,
1169
1180
  `Litecanvas' "width" option should be null or a positive number`
1170
1181
  );
1171
1182
  DEV: assert(
1172
- null === instance.HEIGHT || instance.HEIGHT > 0,
1183
+ null == instance.HEIGHT || instance.HEIGHT > 0,
1173
1184
  `Litecanvas' "width" option should be null or a positive number`
1174
1185
  );
1186
+ DEV: assert(
1187
+ null == instance.HEIGHT || instance.WIDTH > 0 && instance.HEIGHT > 0,
1188
+ `Litecanvas' "width" is required when "heigth" is passed`
1189
+ );
1175
1190
  instance.setvar("CANVAS", _canvas);
1176
1191
  _ctx = _canvas.getContext("2d");
1177
1192
  on(_canvas, "click", () => root.focus());
1178
- if (instance.WIDTH > 0) {
1179
- _fullscreen = false;
1180
- }
1181
1193
  _canvas.style = "";
1182
- _canvas.width = instance.WIDTH;
1183
- _canvas.height = instance.HEIGHT || instance.WIDTH;
1194
+ if (!instance.WIDTH) {
1195
+ instance.WIDTH = root.innerWidth;
1196
+ instance.HEIGHT = root.innerHeight;
1197
+ }
1198
+ instance.resize(instance.WIDTH, instance.HEIGHT, false);
1184
1199
  if (!_canvas.parentNode) document.body.appendChild(_canvas);
1185
1200
  }
1186
- function pageResized() {
1187
- const pageWidth = root.innerWidth, pageHeight = root.innerHeight, styles = _canvas.style;
1188
- styles.display = "block";
1189
- if (_fullscreen) {
1190
- styles.position = "absolute";
1191
- styles.inset = 0;
1192
- instance.setvar("WIDTH", _canvas.width = pageWidth);
1193
- instance.setvar("HEIGHT", _canvas.height = pageHeight);
1194
- } else if (_autoscale) {
1195
- styles.margin = "auto";
1201
+ function onResize() {
1202
+ const styles = _canvas.style;
1203
+ if (_autoscale) {
1204
+ if (!styles.display) {
1205
+ styles.display = "block";
1206
+ styles.margin = "auto";
1207
+ }
1196
1208
  _scale = Math.min(
1197
- pageWidth / instance.WIDTH,
1198
- pageHeight / instance.HEIGHT
1209
+ root.innerWidth / instance.WIDTH,
1210
+ root.innerHeight / instance.HEIGHT
1199
1211
  );
1200
1212
  _scale = (settings.pixelart ? ~~_scale : _scale) || 1;
1201
1213
  styles.width = instance.WIDTH * _scale + "px";
1202
1214
  styles.height = instance.HEIGHT * _scale + "px";
1203
1215
  }
1204
- instance.setvar("CENTERX", instance.WIDTH / 2);
1205
- instance.setvar("CENTERY", instance.HEIGHT / 2);
1206
1216
  if (!settings.antialias || settings.pixelart) {
1207
1217
  _ctx.imageSmoothingEnabled = false;
1208
1218
  styles.imageRendering = "pixelated";
package/dist/dist.js CHANGED
@@ -31,7 +31,6 @@
31
31
  () => elem.removeEventListener(evt, callback, false)
32
32
  );
33
33
  }, isFinite = Number.isFinite, defaults = {
34
- fullscreen: true,
35
34
  width: null,
36
35
  height: null,
37
36
  autoscale: true,
@@ -46,7 +45,7 @@
46
45
  animate: true
47
46
  };
48
47
  settings = Object.assign(defaults, settings);
49
- 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 = {
48
+ let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _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 = {
50
49
  init: null,
51
50
  update: null,
52
51
  draw: null,
@@ -637,9 +636,11 @@
637
636
  * @param {*} [arg4] any data to be passed over the listeners
638
637
  */
639
638
  emit(eventName, arg1, arg2, arg3, arg4) {
640
- triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
641
- triggerEvent(eventName, arg1, arg2, arg3, arg4);
642
- triggerEvent("after:" + eventName, arg1, arg2, arg3, arg4);
639
+ if (_initialized) {
640
+ triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
641
+ triggerEvent(eventName, arg1, arg2, arg3, arg4);
642
+ triggerEvent("after:" + eventName, arg1, arg2, arg3, arg4);
643
+ }
643
644
  },
644
645
  /**
645
646
  * Get a color by index
@@ -673,7 +674,9 @@
673
674
  resize(width, height) {
674
675
  instance.setvar("WIDTH", _canvas.width = width);
675
676
  instance.setvar("HEIGHT", _canvas.height = height);
676
- pageResized();
677
+ instance.setvar("CENTERX", instance.WIDTH / 2);
678
+ instance.setvar("CENTERY", instance.HEIGHT / 2);
679
+ onResize();
677
680
  },
678
681
  /**
679
682
  * The scale of the game's delta time (dt).
@@ -723,10 +726,9 @@
723
726
  for (const [callback, config] of _plugins) {
724
727
  loadPlugin(callback, config);
725
728
  }
726
- if (_fullscreen || _autoscale) {
727
- on(root, "resize", pageResized);
729
+ if (_autoscale) {
730
+ on(root, "resize", onResize);
728
731
  }
729
- pageResized();
730
732
  if (settings.tapEvents) {
731
733
  const _getXY = (pageX, pageY) => [
732
734
  (pageX - _canvas.offsetLeft) / _scale,
@@ -825,18 +827,19 @@
825
827
  });
826
828
  }
827
829
  if (settings.keyboardEvents) {
828
- const _keys = /* @__PURE__ */ new Set();
830
+ const _keyDownList = /* @__PURE__ */ new Set();
829
831
  const iskeydown = (key) => {
830
- return "any" === key ? _keys.size > 0 : _keys.has(key.toLowerCase());
832
+ key = key.toLowerCase();
833
+ return "any" === key ? _keyDownList.size > 0 : _keyDownList.has("space" === key ? " " : key);
831
834
  };
832
835
  instance.setvar("iskeydown", iskeydown);
833
836
  on(root, "keydown", (event) => {
834
- _keys.add(event.key.toLowerCase());
837
+ _keyDownList.add(event.key.toLowerCase());
835
838
  });
836
839
  on(root, "keyup", (event) => {
837
- _keys.delete(event.key.toLowerCase());
840
+ _keyDownList.delete(event.key.toLowerCase());
838
841
  });
839
- on(root, "blur", () => _keys.clear());
842
+ on(root, "blur", () => _keyDownList.clear());
840
843
  }
841
844
  if (settings.pauseOnBlur) {
842
845
  on(root, "blur", () => {
@@ -859,21 +862,22 @@
859
862
  }
860
863
  let updated = 0, frameTime = (now - _lastFrameTime) / 1e3;
861
864
  _lastFrameTime = now;
862
- if (frameTime > _deltaTime * 30)
863
- return void 0;
864
- _accumulated += frameTime;
865
- if (!_animated) {
866
- _accumulated = _deltaTime;
867
- }
868
- for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
869
- instance.emit("update", _deltaTime * _timeScale);
870
- instance.setvar(
871
- "ELAPSED",
872
- instance.ELAPSED + _deltaTime * _timeScale
873
- );
874
- updated++;
865
+ if (frameTime > _deltaTime * 30) {
866
+ } else {
867
+ _accumulated += frameTime;
868
+ if (!_animated) {
869
+ _accumulated = _deltaTime;
870
+ }
871
+ for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
872
+ instance.emit("update", _deltaTime * _timeScale);
873
+ instance.setvar(
874
+ "ELAPSED",
875
+ instance.ELAPSED + _deltaTime * _timeScale
876
+ );
877
+ updated++;
878
+ }
875
879
  }
876
- if (updated) {
880
+ if (updated || !_animated) {
877
881
  instance.textalign("start", "top");
878
882
  instance.emit("draw");
879
883
  }
@@ -883,34 +887,29 @@
883
887
  instance.setvar("CANVAS", _canvas);
884
888
  _ctx = _canvas.getContext("2d");
885
889
  on(_canvas, "click", () => root.focus());
886
- if (instance.WIDTH > 0) {
887
- _fullscreen = false;
888
- }
889
890
  _canvas.style = "";
890
- _canvas.width = instance.WIDTH;
891
- _canvas.height = instance.HEIGHT || instance.WIDTH;
891
+ if (!instance.WIDTH) {
892
+ instance.WIDTH = root.innerWidth;
893
+ instance.HEIGHT = root.innerHeight;
894
+ }
895
+ instance.resize(instance.WIDTH, instance.HEIGHT, false);
892
896
  if (!_canvas.parentNode) document.body.appendChild(_canvas);
893
897
  }
894
- function pageResized() {
895
- const pageWidth = root.innerWidth, pageHeight = root.innerHeight, styles = _canvas.style;
896
- styles.display = "block";
897
- if (_fullscreen) {
898
- styles.position = "absolute";
899
- styles.inset = 0;
900
- instance.setvar("WIDTH", _canvas.width = pageWidth);
901
- instance.setvar("HEIGHT", _canvas.height = pageHeight);
902
- } else if (_autoscale) {
903
- styles.margin = "auto";
898
+ function onResize() {
899
+ const styles = _canvas.style;
900
+ if (_autoscale) {
901
+ if (!styles.display) {
902
+ styles.display = "block";
903
+ styles.margin = "auto";
904
+ }
904
905
  _scale = Math.min(
905
- pageWidth / instance.WIDTH,
906
- pageHeight / instance.HEIGHT
906
+ root.innerWidth / instance.WIDTH,
907
+ root.innerHeight / instance.HEIGHT
907
908
  );
908
909
  _scale = (settings.pixelart ? ~~_scale : _scale) || 1;
909
910
  styles.width = instance.WIDTH * _scale + "px";
910
911
  styles.height = instance.HEIGHT * _scale + "px";
911
912
  }
912
- instance.setvar("CENTERX", instance.WIDTH / 2);
913
- instance.setvar("CENTERY", instance.HEIGHT / 2);
914
913
  if (!settings.antialias || settings.pixelart) {
915
914
  _ctx.imageSmoothingEnabled = false;
916
915
  styles.imageRendering = "pixelated";
package/dist/dist.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e=new AudioContext,t=(t=1,a=.05,l=220,n=0,i=0,o=.1,r=0,s=1,c=0,f=0,u=0,d=0,p=0,h=0,g=0,m=0,v=0,E=1,b=0,w=0,T=0)=>{let x=Math,H=2*x.PI,y=c*=500*H/44100/44100,I=l*=(1-a+2*a*x.random(a=[]))*H/44100,D=0,S=0,A=0,k=1,C=0,L=0,X=0,P=T<0?-1:1,z=H*P*T*2/44100,M=x.cos(z),O=x.sin,Y=O(z)/4,F=1+Y,W=-2*M/F,_=(1-Y)/F,R=(1+P*M)/2/F,G=-(P+M)/F,N=0,B=0,U=0,q=0;for(n=44100*n+9,b*=44100,i*=44100,o*=44100,v*=44100,f*=500*H/85766121e6,g*=H/44100,u*=H/44100,d*=44100,p=44100*p|0,t*=.3*(globalThis.zzfxV||1),P=n+b+i+o+v|0;A<P;a[A++]=X*t)++L%(100*m|0)||(X=r?1<r?2<r?3<r?O(D*D):x.max(x.min(x.tan(D),1),-1):1-(2*D/H%2+2)%2:1-4*x.abs(x.round(D/H)-D/H):O(D),X=(p?1-w+w*O(H*A/p):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<P-v?(P-A-v)/o*E:0),X=v?X/2+(v>A?0:(A<P-v?1:(P-A)/v)*a[A-v|0]/2/t):X,T&&(X=q=R*N+G*(N=B)+R*(B=X)-_*U-W*(U=q))),D+=(z=(l+=c+=f)*x.cos(g*S++))+z*h*O(A**5),k&&++k>d&&(l+=u,I+=u,k=0),!p||++C%p||(l=I,c=y,k=k||1);(t=e.createBuffer(1,P,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,o=requestAnimationFrame,r=[],s=(e,t,a)=>{e.addEventListener(t,a,!1),r.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"),d=e.fullscreen,p=e.autoscale,h=e.animate,g=1,m,v=.5,E=1,b,w,T=0,x,H="sans-serif",y=32,I=Date.now(),D=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],TWO_PI:i,HALF_PI:n/2,lerp:(e,t,a)=>a*(t-e)+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 o=(e-t)/(a-t)*(n-l)+l;return i?k.clamp(o,l,n):o},norm:(e,t,a)=>k.map(e,t,a,0,1),rand:(e=0,t=1)=>(I=(1664525*I+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>Math.floor(k.rand(e,t+1)),seed:e=>null==e?I:I=~~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),o=.5*(0!==v&&~~t==~~l);m.moveTo(~~e+i,~~t+o),m.lineTo(~~a+i,~~l+o),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} ${y}px ${H}`,m.fillStyle=k.getcolor(l),m.fillText(a,~~e,~~t)},textfont(e){H=e},textsize(e){y=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,o=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=o,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,o,r)=>e<n+o&&e+a>n&&t<i+r&&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){P("before:"+e,t,a,l,n),P(e,t,a,l,n),P("after:"+e,t,a,l,n)},getcolor:e=>a[~~e%a.length],setvar(e,t){k[e]=t,D&&(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"),r))e();if(cancelAnimationFrame(x),S=!1,D){for(let e in k)delete l[e];delete l.__litecanvas}}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,round,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))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((d||p)&&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,o=e=>e.preventDefault(),r=!1;s(u,"mousedown",t=>{if(0===t.button){o(t);let[l,n]=e(t.pageX,t.pageY);k.emit("tap",l,n,0),a(0,l,n),r=!0}}),s(u,"mouseup",a=>{if(0===a.button){o(a);let l=t.get(0),[n,s]=e(a.pageX,a.pageY);i(l)&&k.emit("tapped",l.startX,l.startY,0),k.emit("untap",n,s,0),t.delete(0),r=!1}}),s(u,"mousemove",t=>{o(t);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,"touchstart",t=>{for(let l of(o(t),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(o(t),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 c=e=>{o(e);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",c),s(u,"touchcancel",c),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=o(L))})),k.setfps(60),k.emit("init",k),b=performance.now(),x=o(L)}function L(e){h&&(x=o(L));let t=0,a=(e-b)/1e3;if(b=e,!(a>30*w)){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",d?(n.position="absolute",n.inset=0,k.setvar("WIDTH",u.width=t),k.setvar("HEIGHT",u.height=a)):p&&(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,n.imageRendering="pixelated"),k.emit("resized",g),h||o(L)}function P(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);for(let e in a)k.setvar(e,a[e])}if(D){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&&(d=!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",()=>o(C)):o(C),k}})();
1
+ (()=>{var e=new AudioContext,t=(t=1,a=.05,l=220,n=0,i=0,o=.1,r=0,s=1,c=0,f=0,p=0,d=0,u=0,h=0,g=0,m=0,v=0,E=1,b=0,x=0,T=0)=>{let w=Math,y=2*w.PI,H=c*=500*y/44100/44100,I=l*=(1-a+2*a*w.random(a=[]))*y/44100,S=0,D=0,A=0,k=1,C=0,L=0,X=0,z=T<0?-1:1,P=y*z*T*2/44100,M=w.cos(P),O=w.sin,Y=O(P)/4,F=1+Y,W=-2*M/F,_=(1-Y)/F,R=(1+z*M)/2/F,G=-(z+M)/F,N=0,B=0,U=0,q=0;for(n=44100*n+9,b*=44100,i*=44100,o*=44100,v*=44100,f*=500*y/85766121e6,g*=y/44100,p*=y/44100,d*=44100,u=44100*u|0,t*=.3*(globalThis.zzfxV||1),z=n+b+i+o+v|0;A<z;a[A++]=X*t)++L%(100*m|0)||(X=r?1<r?2<r?3<r?O(S*S):w.max(w.min(w.tan(S),1),-1):1-(2*S/y%2+2)%2:1-4*w.abs(w.round(S/y)-S/y):O(S),X=(u?1-x+x*O(y*A/u):1)*(X<0?-1:1)*w.abs(X)**s*(A<n?A/n:A<n+b?1-(A-n)/b*(1-E):A<n+b+i?E:A<z-v?(z-A-v)/o*E:0),X=v?X/2+(v>A?0:(A<z-v?1:(z-A)/v)*a[A-v|0]/2/t):X,T&&(X=q=R*N+G*(N=B)+R*(B=X)-_*U-W*(U=q))),S+=(P=(l+=c+=f)*w.cos(g*D++))+P*h*O(A**5),k&&++k>d&&(l+=p,I+=p,k=0),!u||++C%u||(l=I,c=H,k=k||1);(t=e.createBuffer(1,z,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,o=requestAnimationFrame,r=[],s=(e,t,a)=>{e.addEventListener(t,a,!1),r.push(()=>e.removeEventListener(t,a,!1))};e=Object.assign({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"),d=e.autoscale,u=e.animate,h=1,g,m=.5,v=1,E,b,x=0,T,w="sans-serif",y=32,H=Date.now(),I=e.global,S={init:null,update:null,draw:null,resized:null,tap:null,untap:null,tapping:null,tapped:null},D={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],TWO_PI:i,HALF_PI:n/2,lerp:(e,t,a)=>a*(t-e)+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 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)=>(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?g.clearRect(0,0,g.canvas.width,g.canvas.height):A.rectfill(0,0,g.canvas.width,g.canvas.height,e)},rect(e,t,a,l,n,i=null){g.beginPath(),g[i?"roundRect":"rect"](~~e-m,~~t-m,~~a+2*m,~~l+2*m,i),A.stroke(n)},rectfill(e,t,a,l,n,i=null){g.beginPath(),g[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),A.fill(n)},circ(e,t,a,l){g.beginPath(),g.arc(~~e,~~t,~~a,0,i),A.stroke(l)},circfill(e,t,a,l){g.beginPath(),g.arc(~~e,~~t,~~a,0,i),A.fill(l)},line(e,t,a,l,n){g.beginPath();let i=.5*(0!==m&&~~e==~~a),o=.5*(0!==m&&~~t==~~l);g.moveTo(~~e+i,~~t+o),g.lineTo(~~a+i,~~l+o),A.stroke(n)},linewidth(e){g.lineWidth=~~e,m=.5*(~~e%2!=0)},linedash(e,t=0){g.setLineDash(e),g.lineDashOffset=t},text(e,t,a,l=3,n="normal"){g.font=`${n} ${y}px ${w}`,g.fillStyle=A.getcolor(l),g.fillText(a,~~e,~~t)},textfont(e){w=e},textsize(e){y=e},textalign(e,t){e&&(g.textAlign=e),t&&(g.textBaseline=t)},image(e,t,a){g.drawImage(a,~~e,~~t)},paint(e,t,a,l={}){let n=l.canvas||new OffscreenCanvas(1,1),i=l.scale||1,o=g;if(n.width=e*i,n.height=t*i,(g=n.getContext("2d")).scale(i,i),a.push){let e=0,t=0;for(let l of(g.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(g);return g=o,n},ctx:e=>(e&&(g=e),g),push:()=>g.save(),pop:()=>g.restore(),translate:(e,t)=>g.translate(~~e,~~t),scale:(e,t)=>g.scale(e,t||e),rotate:e=>g.rotate(e),alpha(e){g.globalAlpha=A.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){g.fillStyle=A.getcolor(e),t?g.fill(t):g.fill()},stroke(e,t){g.strokeStyle=A.getcolor(e),t?g.stroke(t):g.stroke()},clip(e){g.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,o,r)=>e<n+o&&e+a>n&&t<i+r&&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){c&&(X("before:"+e,t,a,l,n),X(e,t,a,l,n),X("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",p.width=e),A.setvar("HEIGHT",p.height=t),A.setvar("CENTERX",A.WIDTH/2),A.setvar("CENTERY",A.HEIGHT/2),L()},timescale(e){v=e},setfps(e){b=1/~~e},quit(){for(let e of(A.emit("quit"),r))e();if(cancelAnimationFrame(T),S=!1,I){for(let e in A)delete l[e];delete l.__litecanvas}}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,round,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))A[e]=Math[e];function k(){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(d&&s(l,"resize",L),e.tapEvents){let e=(e,t)=>[(e-p.offsetLeft)/h,(t-p.offsetTop)/h],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,o=e=>e.preventDefault(),r=!1;s(p,"mousedown",t=>{if(0===t.button){o(t);let[l,n]=e(t.pageX,t.pageY);A.emit("tap",l,n,0),a(0,l,n),r=!0}}),s(p,"mouseup",a=>{if(0===a.button){o(a);let l=t.get(0),[n,s]=e(a.pageX,a.pageY);i(l)&&A.emit("tapped",l.startX,l.startY,0),A.emit("untap",n,s,0),t.delete(0),r=!1}}),s(p,"mousemove",t=>{o(t);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(p,"touchstart",t=>{for(let l of(o(t),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(p,"touchmove",t=>{for(let a of(o(t),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 c=e=>{o(e);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(p,"touchend",c),s(p,"touchcancel",c),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=t.toLowerCase())?e.size>0:e.has("space"===t?" ":t)),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",()=>{T=cancelAnimationFrame(T)}),s(l,"focus",()=>{T||(T=o(C))})),A.setfps(60),A.emit("init",A),E=performance.now(),T=o(C)}function C(e){u&&(T=o(C));let t=0,a=(e-E)/1e3;if(E=e,a>30*b);else for(x+=a,u||(x=b);x>=b;x-=b)A.emit("update",b*v),A.setvar("ELAPSED",A.ELAPSED+b*v),t++;(t||!u)&&(A.textalign("start","top"),A.emit("draw"))}function L(){let t=p.style;d&&(t.display||(t.display="block",t.margin="auto"),h=Math.min(l.innerWidth/A.WIDTH,l.innerHeight/A.HEIGHT),h=(e.pixelart?~~h:h)||1,t.width=A.WIDTH*h+"px",t.height=A.HEIGHT*h+"px"),(!e.antialias||e.pixelart)&&(g.imageSmoothingEnabled=!1,t.imageRendering="pixelated"),A.emit("resized",h),u||o(C)}function X(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,D,t);for(let e in a)A.setvar(e,a[e])}if(I){if(l.__litecanvas)throw"global litecanvas already instantiated";Object.assign(l,A),l.__litecanvas=A}return p="string"==typeof p?document.querySelector(p):p,A.setvar("CANVAS",p),g=p.getContext("2d"),s(p,"click",()=>l.focus()),p.style="",A.WIDTH||(A.WIDTH=l.innerWidth,A.HEIGHT=l.innerHeight),A.resize(A.WIDTH,A.HEIGHT,!1),p.parentNode||document.body.appendChild(p),"loading"===document.readyState?s(l,"DOMContentLoaded",()=>o(k)):o(k),A}})();
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.75.1",
3
+ "version": "0.77.0",
4
4
  "description": "Lightweight HTML5 canvas game engine suitable for small projects and creative coding. Inspired by PICO-8 and P5/Processing.",
5
5
  "license": "MIT",
6
6
  "author": "Luiz Bills <luizbills@pm.me>",
7
7
  "contributors": [],
8
8
  "devDependencies": {
9
- "@swc/core": "^1.11.7",
9
+ "@swc/core": "^1.11.8",
10
10
  "ava": "^6.2.0",
11
- "esbuild": "^0.25.0",
11
+ "esbuild": "^0.25.1",
12
12
  "gzip-size": "^7.0.0",
13
13
  "prettier": "^3.5.3"
14
14
  },
package/src/index.js CHANGED
@@ -26,7 +26,6 @@ export default function litecanvas(settings = {}) {
26
26
  isFinite = Number.isFinite,
27
27
  /** @type {LitecanvasOptions} */
28
28
  defaults = {
29
- fullscreen: true,
30
29
  width: null,
31
30
  height: null,
32
31
  autoscale: true,
@@ -51,8 +50,6 @@ export default function litecanvas(settings = {}) {
51
50
  /** @type {HTMLCanvasElement|string} _canvas */
52
51
  _canvas = settings.canvas || document.createElement('canvas'),
53
52
  /** @type {boolean} */
54
- _fullscreen = settings.fullscreen,
55
- /** @type {boolean} */
56
53
  _autoscale = settings.autoscale,
57
54
  /** @type {boolean} */
58
55
  _animated = settings.animate,
@@ -1069,10 +1066,11 @@ export default function litecanvas(settings = {}) {
1069
1066
  'string' === typeof eventName,
1070
1067
  'emit: 1st param must be a string'
1071
1068
  )
1072
-
1073
- triggerEvent('before:' + eventName, arg1, arg2, arg3, arg4)
1074
- triggerEvent(eventName, arg1, arg2, arg3, arg4)
1075
- triggerEvent('after:' + eventName, arg1, arg2, arg3, arg4)
1069
+ if (_initialized) {
1070
+ triggerEvent('before:' + eventName, arg1, arg2, arg3, arg4)
1071
+ triggerEvent(eventName, arg1, arg2, arg3, arg4)
1072
+ triggerEvent('after:' + eventName, arg1, arg2, arg3, arg4)
1073
+ }
1076
1074
  },
1077
1075
 
1078
1076
  /**
@@ -1118,12 +1116,22 @@ export default function litecanvas(settings = {}) {
1118
1116
  * @param {number} height
1119
1117
  */
1120
1118
  resize(width, height) {
1121
- DEV: assert(isFinite(width), 'resize: 1st param must be a number')
1122
- DEV: assert(isFinite(height), 'resize: 2nd param must be a number')
1119
+ DEV: assert(
1120
+ isFinite(width) && width > 0,
1121
+ 'resize: 1st param must be a number'
1122
+ )
1123
+ DEV: assert(
1124
+ isFinite(height) && height > 0,
1125
+ 'resize: 2nd param must be a number'
1126
+ )
1123
1127
 
1124
1128
  instance.setvar('WIDTH', (_canvas.width = width))
1125
1129
  instance.setvar('HEIGHT', (_canvas.height = height))
1126
- pageResized()
1130
+
1131
+ instance.setvar('CENTERX', instance.WIDTH / 2)
1132
+ instance.setvar('CENTERY', instance.HEIGHT / 2)
1133
+
1134
+ onResize()
1127
1135
  },
1128
1136
 
1129
1137
  /**
@@ -1184,7 +1192,7 @@ export default function litecanvas(settings = {}) {
1184
1192
  function init() {
1185
1193
  _initialized = true
1186
1194
 
1187
- // add listeners for default events
1195
+ // setup default event listeners
1188
1196
  const source = settings.loop ? settings.loop : root
1189
1197
  for (const event in _events) {
1190
1198
  if (source[event]) instance.listen(event, source[event])
@@ -1195,13 +1203,11 @@ export default function litecanvas(settings = {}) {
1195
1203
  loadPlugin(callback, config)
1196
1204
  }
1197
1205
 
1198
- // listen window resize event
1199
- if (_fullscreen || _autoscale) {
1200
- on(root, 'resize', pageResized)
1206
+ // listen window resize event when "autoscale" is enabled
1207
+ if (_autoscale) {
1208
+ on(root, 'resize', onResize)
1201
1209
  }
1202
1210
 
1203
- pageResized()
1204
-
1205
1211
  // default mouse/touch handlers
1206
1212
  if (settings.tapEvents) {
1207
1213
  const _getXY = (pageX, pageY) => [
@@ -1325,13 +1331,11 @@ export default function litecanvas(settings = {}) {
1325
1331
 
1326
1332
  if (settings.keyboardEvents) {
1327
1333
  /** @type {Set<string>} */
1328
- const _keys = new Set()
1334
+ const _keyDownList = new Set()
1329
1335
 
1330
1336
  /**
1331
- * Checks if a key is currently pressed in your keyboard.
1332
- * Notes:
1333
- * - to check the space key use `iskeydown(" ")`.
1334
- * - you can check if any key is pressed using `iskeydown("any")`.
1337
+ * Checks if a which key is pressed on the keyboard.
1338
+ * Note: use `iskeydown("any")` to check for any key pressed.
1335
1339
  *
1336
1340
  * @param {string} key
1337
1341
  * @returns {boolean}
@@ -1342,22 +1346,24 @@ export default function litecanvas(settings = {}) {
1342
1346
  'iskeydown: 1st param must be a string'
1343
1347
  )
1344
1348
 
1349
+ key = key.toLowerCase()
1350
+
1345
1351
  return 'any' === key
1346
- ? _keys.size > 0
1347
- : _keys.has(key.toLowerCase())
1352
+ ? _keyDownList.size > 0
1353
+ : _keyDownList.has('space' === key ? ' ' : key)
1348
1354
  }
1349
1355
 
1350
1356
  instance.setvar('iskeydown', iskeydown)
1351
1357
 
1352
1358
  on(root, 'keydown', (/** @type {KeyboardEvent} */ event) => {
1353
- _keys.add(event.key.toLowerCase())
1359
+ _keyDownList.add(event.key.toLowerCase())
1354
1360
  })
1355
1361
 
1356
1362
  on(root, 'keyup', (/** @type {KeyboardEvent} */ event) => {
1357
- _keys.delete(event.key.toLowerCase())
1363
+ _keyDownList.delete(event.key.toLowerCase())
1358
1364
  })
1359
1365
 
1360
- on(root, 'blur', () => _keys.clear())
1366
+ on(root, 'blur', () => _keyDownList.clear())
1361
1367
  }
1362
1368
 
1363
1369
  // listen browser focus/blur events and pause the update/draw loop
@@ -1395,25 +1401,26 @@ export default function litecanvas(settings = {}) {
1395
1401
 
1396
1402
  _lastFrameTime = now
1397
1403
 
1398
- if (frameTime > _deltaTime * 30)
1399
- return console.log('skipping too long frame')
1400
-
1401
- _accumulated += frameTime
1404
+ if (frameTime > _deltaTime * 30) {
1405
+ console.log('skipping too long frame')
1406
+ } else {
1407
+ _accumulated += frameTime
1402
1408
 
1403
- if (!_animated) {
1404
- _accumulated = _deltaTime
1405
- }
1409
+ if (!_animated) {
1410
+ _accumulated = _deltaTime
1411
+ }
1406
1412
 
1407
- for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
1408
- instance.emit('update', _deltaTime * _timeScale)
1409
- instance.setvar(
1410
- 'ELAPSED',
1411
- instance.ELAPSED + _deltaTime * _timeScale
1412
- )
1413
- updated++
1413
+ for (; _accumulated >= _deltaTime; _accumulated -= _deltaTime) {
1414
+ instance.emit('update', _deltaTime * _timeScale)
1415
+ instance.setvar(
1416
+ 'ELAPSED',
1417
+ instance.ELAPSED + _deltaTime * _timeScale
1418
+ )
1419
+ updated++
1420
+ }
1414
1421
  }
1415
1422
 
1416
- if (updated) {
1423
+ if (updated || !_animated) {
1417
1424
  instance.textalign('start', 'top') // default values for textAlign & textBaseline
1418
1425
  instance.emit('draw')
1419
1426
  }
@@ -1431,57 +1438,56 @@ export default function litecanvas(settings = {}) {
1431
1438
  'Invalid canvas element'
1432
1439
  )
1433
1440
  DEV: assert(
1434
- null === instance.WIDTH || instance.WIDTH > 0,
1441
+ null == instance.WIDTH || instance.WIDTH > 0,
1435
1442
  'Litecanvas\' "width" option should be null or a positive number'
1436
1443
  )
1437
1444
  DEV: assert(
1438
- null === instance.HEIGHT || instance.HEIGHT > 0,
1445
+ null == instance.HEIGHT || instance.HEIGHT > 0,
1439
1446
  'Litecanvas\' "width" option should be null or a positive number'
1440
1447
  )
1448
+ DEV: assert(
1449
+ null == instance.HEIGHT ||
1450
+ (instance.WIDTH > 0 && instance.HEIGHT > 0),
1451
+ 'Litecanvas\' "width" is required when "heigth" is passed'
1452
+ )
1441
1453
 
1442
1454
  instance.setvar('CANVAS', _canvas)
1443
1455
  _ctx = _canvas.getContext('2d')
1444
1456
 
1445
1457
  on(_canvas, 'click', () => root.focus())
1446
1458
 
1447
- // disable fullscreen if a width is specified
1448
- if (instance.WIDTH > 0) {
1449
- _fullscreen = false
1459
+ _canvas.style = ''
1460
+
1461
+ // If width is not set, the canvas will have the size of the page width.
1462
+ if (!instance.WIDTH) {
1463
+ instance.WIDTH = root.innerWidth
1464
+ instance.HEIGHT = root.innerHeight
1450
1465
  }
1451
1466
 
1452
- _canvas.style = ''
1453
- _canvas.width = instance.WIDTH
1454
- _canvas.height = instance.HEIGHT || instance.WIDTH
1467
+ instance.resize(instance.WIDTH, instance.HEIGHT, false)
1455
1468
 
1456
1469
  if (!_canvas.parentNode) document.body.appendChild(_canvas)
1457
1470
  }
1458
1471
 
1459
- function pageResized() {
1460
- const pageWidth = root.innerWidth,
1461
- pageHeight = root.innerHeight,
1462
- styles = _canvas.style
1472
+ function onResize() {
1473
+ const styles = _canvas.style
1463
1474
 
1464
- styles.display = 'block'
1475
+ if (_autoscale) {
1476
+ if (!styles.display) {
1477
+ styles.display = 'block'
1478
+ styles.margin = 'auto'
1479
+ }
1465
1480
 
1466
- if (_fullscreen) {
1467
- styles.position = 'absolute'
1468
- styles.inset = 0
1469
- instance.setvar('WIDTH', (_canvas.width = pageWidth))
1470
- instance.setvar('HEIGHT', (_canvas.height = pageHeight))
1471
- } else if (_autoscale) {
1472
- styles.margin = 'auto'
1473
1481
  _scale = Math.min(
1474
- pageWidth / instance.WIDTH,
1475
- pageHeight / instance.HEIGHT
1482
+ root.innerWidth / instance.WIDTH,
1483
+ root.innerHeight / instance.HEIGHT
1476
1484
  )
1477
1485
  _scale = (settings.pixelart ? ~~_scale : _scale) || 1
1486
+
1478
1487
  styles.width = instance.WIDTH * _scale + 'px'
1479
1488
  styles.height = instance.HEIGHT * _scale + 'px'
1480
1489
  }
1481
1490
 
1482
- instance.setvar('CENTERX', instance.WIDTH / 2)
1483
- instance.setvar('CENTERY', instance.HEIGHT / 2)
1484
-
1485
1491
  // restore canvas image rendering properties
1486
1492
  if (!settings.antialias || settings.pixelart) {
1487
1493
  _ctx.imageSmoothingEnabled = false
@@ -1490,6 +1496,7 @@ export default function litecanvas(settings = {}) {
1490
1496
 
1491
1497
  instance.emit('resized', _scale)
1492
1498
 
1499
+ // force redraw
1493
1500
  if (!_animated) {
1494
1501
  raf(drawFrame)
1495
1502
  }
package/src/types.js CHANGED
@@ -1,8 +1,6 @@
1
1
  /**
2
2
  * @typedef LitecanvasOptions
3
3
  * @type {object}
4
- * @property {number} [fps=60]
5
- * @property {boolean} [fullscreen=true]
6
4
  * @property {number} [width]
7
5
  * @property {number} [height]
8
6
  * @property {boolean} [pauseOnBlur=true]
package/types/index.d.ts CHANGED
@@ -487,10 +487,8 @@ declare global {
487
487
 
488
488
  /** UTILS API */
489
489
  /**
490
- * Checks if a key is currently pressed in your keyboard.
491
- * Notes:
492
- * - to check the space key use `iskeydown(" ")`.
493
- * - you can check if any key is pressed using `iskeydown("any")`.
490
+ * Checks if a which key is pressed on the keyboard.
491
+ * Note: use `iskeydown("any")` to check for any key pressed.
494
492
  *
495
493
  * @param key
496
494
  * @returns `true` if the which key is down
package/types/types.d.ts CHANGED
@@ -465,10 +465,8 @@ type LitecanvasInstance = {
465
465
 
466
466
  /** UTILS API */
467
467
  /**
468
- * Checks if a key is currently pressed in your keyboard.
469
- * Notes:
470
- * - to check the space key use `iskeydown(" ")`.
471
- * - you can check if any key is pressed using `iskeydown("any")`.
468
+ * Checks if a which key is pressed on the keyboard.
469
+ * Note: use `iskeydown("any")` to check for any key pressed.
472
470
  *
473
471
  * @param key
474
472
  * @returns `true` if the which key is down
@@ -579,15 +577,7 @@ type LitecanvasInstance = {
579
577
 
580
578
  type LitecanvasOptions = {
581
579
  /**
582
- * target FPS
583
- */
584
- fps?: number
585
- /**
586
- * Makes the canvas fills the entire page. By default is `true`.
587
- */
588
- fullscreen?: boolean
589
- /**
590
- * The game screen width. If specified, disables fullscreen.
580
+ * The game screen width. If not set, the canvas will have the size of the webpage.
591
581
  */
592
582
  width?: number
593
583
  /**