litecanvas 0.102.2 → 0.103.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/dist/dist.dev.js +30 -32
- package/dist/dist.js +24 -23
- package/dist/dist.min.js +1 -1
- package/package.json +7 -7
- package/src/index.js +33 -32
- package/src/version.js +1 -1
- package/types/global.d.ts +7 -6
- package/types/types.d.ts +7 -6
package/dist/dist.dev.js
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
// src/version.js
|
|
22
|
-
var version = "0.
|
|
22
|
+
var version = "0.103.0";
|
|
23
23
|
|
|
24
24
|
// src/index.js
|
|
25
25
|
function litecanvas(settings = {}) {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
keyboardEvents: true
|
|
38
38
|
};
|
|
39
39
|
settings = Object.assign(defaults, settings);
|
|
40
|
-
let _initialized = false, _paused = true, _canvas,
|
|
40
|
+
let _initialized = false, _paused = true, _canvas, _canvasScale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _defaultTextColor = 3, _fontFamily = "sans-serif", _fontSize = 20, _fontLineHeight = 1.2, _rngSeed = Date.now(), _colorPalette = defaultPalette, _colorPaletteState = [], _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1], _coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized", _mathFunctions = "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp", _eventListeners = {};
|
|
41
41
|
const instance = {
|
|
42
42
|
/** @type {number} */
|
|
43
43
|
W: 0,
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
DEV: assert(isNumber(start), "[litecanvas] lerp() 1st param must be a number");
|
|
81
81
|
DEV: assert(isNumber(end), "[litecanvas] lerp() 2nd param must be a number");
|
|
82
82
|
DEV: assert(isNumber(t), "[litecanvas] lerp() 3rd param must be a number");
|
|
83
|
-
return t * (end - start)
|
|
83
|
+
return start + t * (end - start);
|
|
84
84
|
},
|
|
85
85
|
/**
|
|
86
86
|
* Convert degrees to radians
|
|
@@ -143,6 +143,22 @@
|
|
|
143
143
|
if (value > max) return max;
|
|
144
144
|
return value;
|
|
145
145
|
},
|
|
146
|
+
/**
|
|
147
|
+
* Calculates the distance between a point (x1, y1) to another (x2, y2).
|
|
148
|
+
*
|
|
149
|
+
* @param {number} x1
|
|
150
|
+
* @param {number} y1
|
|
151
|
+
* @param {number} x2
|
|
152
|
+
* @param {number} y2
|
|
153
|
+
* @returns {number}
|
|
154
|
+
*/
|
|
155
|
+
dist: (x1, y1, x2, y2) => {
|
|
156
|
+
DEV: assert(isNumber(x1), "[litecanvas] dist() 1st param must be a number");
|
|
157
|
+
DEV: assert(isNumber(y1), "[litecanvas] dist() 2nd param must be a number");
|
|
158
|
+
DEV: assert(isNumber(x2), "[litecanvas] dist() 3rd param must be a number");
|
|
159
|
+
DEV: assert(isNumber(y2), "[litecanvas] dist() 4th param must be a number");
|
|
160
|
+
return math.hypot(x2 - x1, y2 - y1);
|
|
161
|
+
},
|
|
146
162
|
/**
|
|
147
163
|
* Wraps a number between `min` (inclusive) and `max` (exclusive).
|
|
148
164
|
*
|
|
@@ -205,24 +221,6 @@
|
|
|
205
221
|
);
|
|
206
222
|
return instance.map(value, start, stop, 0, 1);
|
|
207
223
|
},
|
|
208
|
-
/**
|
|
209
|
-
* Interpolate between 2 values using a periodic function.
|
|
210
|
-
*
|
|
211
|
-
* @param {number} from - the lower bound
|
|
212
|
-
* @param {number} to - the higher bound
|
|
213
|
-
* @param {number} t - value passed to the periodic function
|
|
214
|
-
* @param {(n: number) => number} [fn] - the periodic function (which default to `Math.sin`)
|
|
215
|
-
*/
|
|
216
|
-
wave: (from, to, t, fn = Math.sin) => {
|
|
217
|
-
DEV: assert(isNumber(from), "[litecanvas] wave() 1st param must be a number");
|
|
218
|
-
DEV: assert(isNumber(to), "[litecanvas] wave() 2nd param must be a number");
|
|
219
|
-
DEV: assert(isNumber(t), "[litecanvas] wave() 3rd param must be a number");
|
|
220
|
-
DEV: assert(
|
|
221
|
-
"function" === typeof fn,
|
|
222
|
-
"[litecanvas] wave() 4rd param must be a function (n: number) => number"
|
|
223
|
-
);
|
|
224
|
-
return from + (fn(t) + 1) / 2 * (to - from);
|
|
225
|
-
},
|
|
226
224
|
/** RNG API */
|
|
227
225
|
/**
|
|
228
226
|
* Generates a pseudorandom float between min (inclusive) and max (exclusive)
|
|
@@ -256,7 +254,7 @@
|
|
|
256
254
|
DEV: assert(isNumber(min), "[litecanvas] randi() 1st param must be a number");
|
|
257
255
|
DEV: assert(isNumber(max), "[litecanvas] randi() 2nd param must be a number");
|
|
258
256
|
DEV: assert(
|
|
259
|
-
|
|
257
|
+
min <= max,
|
|
260
258
|
"[litecanvas] randi() the 1st param must be less than the 2nd param"
|
|
261
259
|
);
|
|
262
260
|
return math.floor(instance.rand(min, max + 1));
|
|
@@ -911,7 +909,7 @@
|
|
|
911
909
|
eventName = lowerCase(eventName);
|
|
912
910
|
_eventListeners[eventName] = _eventListeners[eventName] || /* @__PURE__ */ new Set();
|
|
913
911
|
_eventListeners[eventName].add(callback);
|
|
914
|
-
return () => _eventListeners
|
|
912
|
+
return () => _eventListeners[eventName]?.delete(callback);
|
|
915
913
|
},
|
|
916
914
|
/**
|
|
917
915
|
* Call all listeners attached to a game event
|
|
@@ -1041,7 +1039,7 @@
|
|
|
1041
1039
|
// 2
|
|
1042
1040
|
_fpsInterval / 1e3,
|
|
1043
1041
|
// 3
|
|
1044
|
-
|
|
1042
|
+
_canvasScale,
|
|
1045
1043
|
// 4
|
|
1046
1044
|
_eventListeners,
|
|
1047
1045
|
// 5
|
|
@@ -1130,8 +1128,8 @@
|
|
|
1130
1128
|
* @param {MouseEvent | Touch} ev
|
|
1131
1129
|
*/
|
|
1132
1130
|
(ev) => [
|
|
1133
|
-
(ev.pageX - _canvas.offsetLeft) /
|
|
1134
|
-
(ev.pageY - _canvas.offsetTop) /
|
|
1131
|
+
(ev.pageX - _canvas.offsetLeft) / _canvasScale,
|
|
1132
|
+
(ev.pageY - _canvas.offsetTop) / _canvasScale
|
|
1135
1133
|
]
|
|
1136
1134
|
), _taps = /* @__PURE__ */ new Map(), _registerTap = (
|
|
1137
1135
|
/**
|
|
@@ -1342,8 +1340,8 @@
|
|
|
1342
1340
|
);
|
|
1343
1341
|
}
|
|
1344
1342
|
_initialized = true;
|
|
1345
|
-
instance.emit("init", instance);
|
|
1346
1343
|
instance.resume();
|
|
1344
|
+
instance.emit("init", instance);
|
|
1347
1345
|
}
|
|
1348
1346
|
function drawFrame() {
|
|
1349
1347
|
_rafid = raf(drawFrame);
|
|
@@ -1417,14 +1415,14 @@
|
|
|
1417
1415
|
_canvas.style.display = "block";
|
|
1418
1416
|
_canvas.style.margin = "auto";
|
|
1419
1417
|
}
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
_canvas.style.width = width *
|
|
1423
|
-
_canvas.style.height = height *
|
|
1418
|
+
_canvasScale = math.min(innerWidth / width, innerHeight / height);
|
|
1419
|
+
_canvasScale = maxScale > 1 && _canvasScale > maxScale ? maxScale : _canvasScale;
|
|
1420
|
+
_canvas.style.width = width * _canvasScale + "px";
|
|
1421
|
+
_canvas.style.height = height * _canvasScale + "px";
|
|
1424
1422
|
}
|
|
1425
1423
|
_ctx.imageSmoothingEnabled = false;
|
|
1426
1424
|
instance.textalign("start", "top");
|
|
1427
|
-
instance.emit("resized",
|
|
1425
|
+
instance.emit("resized", _canvasScale);
|
|
1428
1426
|
}
|
|
1429
1427
|
function triggerEvent(eventName, arg1, arg2, arg3, arg4) {
|
|
1430
1428
|
if (!_eventListeners[eventName]) return;
|
package/dist/dist.js
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
keyboardEvents: true
|
|
30
30
|
};
|
|
31
31
|
settings = Object.assign(defaults, settings);
|
|
32
|
-
let _initialized = false, _paused = true, _canvas,
|
|
32
|
+
let _initialized = false, _paused = true, _canvas, _canvasScale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _defaultTextColor = 3, _fontFamily = "sans-serif", _fontSize = 20, _fontLineHeight = 1.2, _rngSeed = Date.now(), _colorPalette = defaultPalette, _colorPaletteState = [], _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1], _coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized", _mathFunctions = "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp", _eventListeners = {};
|
|
33
33
|
const instance = {
|
|
34
34
|
/** @type {number} */
|
|
35
35
|
W: 0,
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
* @tutorial https://gamedev.net/tutorials/programming/general-and-gameplay-programming/a-brief-introduction-to-lerp-r4954/
|
|
70
70
|
*/
|
|
71
71
|
lerp: (start, end, t) => {
|
|
72
|
-
return t * (end - start)
|
|
72
|
+
return start + t * (end - start);
|
|
73
73
|
},
|
|
74
74
|
/**
|
|
75
75
|
* Convert degrees to radians
|
|
@@ -118,6 +118,18 @@
|
|
|
118
118
|
if (value > max) return max;
|
|
119
119
|
return value;
|
|
120
120
|
},
|
|
121
|
+
/**
|
|
122
|
+
* Calculates the distance between a point (x1, y1) to another (x2, y2).
|
|
123
|
+
*
|
|
124
|
+
* @param {number} x1
|
|
125
|
+
* @param {number} y1
|
|
126
|
+
* @param {number} x2
|
|
127
|
+
* @param {number} y2
|
|
128
|
+
* @returns {number}
|
|
129
|
+
*/
|
|
130
|
+
dist: (x1, y1, x2, y2) => {
|
|
131
|
+
return math.hypot(x2 - x1, y2 - y1);
|
|
132
|
+
},
|
|
121
133
|
/**
|
|
122
134
|
* Wraps a number between `min` (inclusive) and `max` (exclusive).
|
|
123
135
|
*
|
|
@@ -157,17 +169,6 @@
|
|
|
157
169
|
norm: (value, start, stop) => {
|
|
158
170
|
return instance.map(value, start, stop, 0, 1);
|
|
159
171
|
},
|
|
160
|
-
/**
|
|
161
|
-
* Interpolate between 2 values using a periodic function.
|
|
162
|
-
*
|
|
163
|
-
* @param {number} from - the lower bound
|
|
164
|
-
* @param {number} to - the higher bound
|
|
165
|
-
* @param {number} t - value passed to the periodic function
|
|
166
|
-
* @param {(n: number) => number} [fn] - the periodic function (which default to `Math.sin`)
|
|
167
|
-
*/
|
|
168
|
-
wave: (from, to, t, fn = Math.sin) => {
|
|
169
|
-
return from + (fn(t) + 1) / 2 * (to - from);
|
|
170
|
-
},
|
|
171
172
|
/** RNG API */
|
|
172
173
|
/**
|
|
173
174
|
* Generates a pseudorandom float between min (inclusive) and max (exclusive)
|
|
@@ -627,7 +628,7 @@
|
|
|
627
628
|
eventName = lowerCase(eventName);
|
|
628
629
|
_eventListeners[eventName] = _eventListeners[eventName] || /* @__PURE__ */ new Set();
|
|
629
630
|
_eventListeners[eventName].add(callback);
|
|
630
|
-
return () => _eventListeners
|
|
631
|
+
return () => _eventListeners[eventName]?.delete(callback);
|
|
631
632
|
},
|
|
632
633
|
/**
|
|
633
634
|
* Call all listeners attached to a game event
|
|
@@ -719,7 +720,7 @@
|
|
|
719
720
|
// 2
|
|
720
721
|
_fpsInterval / 1e3,
|
|
721
722
|
// 3
|
|
722
|
-
|
|
723
|
+
_canvasScale,
|
|
723
724
|
// 4
|
|
724
725
|
_eventListeners,
|
|
725
726
|
// 5
|
|
@@ -803,8 +804,8 @@
|
|
|
803
804
|
* @param {MouseEvent | Touch} ev
|
|
804
805
|
*/
|
|
805
806
|
(ev) => [
|
|
806
|
-
(ev.pageX - _canvas.offsetLeft) /
|
|
807
|
-
(ev.pageY - _canvas.offsetTop) /
|
|
807
|
+
(ev.pageX - _canvas.offsetLeft) / _canvasScale,
|
|
808
|
+
(ev.pageY - _canvas.offsetTop) / _canvasScale
|
|
808
809
|
]
|
|
809
810
|
), _taps = /* @__PURE__ */ new Map(), _registerTap = (
|
|
810
811
|
/**
|
|
@@ -1007,8 +1008,8 @@
|
|
|
1007
1008
|
);
|
|
1008
1009
|
}
|
|
1009
1010
|
_initialized = true;
|
|
1010
|
-
instance.emit("init", instance);
|
|
1011
1011
|
instance.resume();
|
|
1012
|
+
instance.emit("init", instance);
|
|
1012
1013
|
}
|
|
1013
1014
|
function drawFrame() {
|
|
1014
1015
|
_rafid = raf(drawFrame);
|
|
@@ -1059,14 +1060,14 @@
|
|
|
1059
1060
|
_canvas.style.display = "block";
|
|
1060
1061
|
_canvas.style.margin = "auto";
|
|
1061
1062
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
_canvas.style.width = width *
|
|
1065
|
-
_canvas.style.height = height *
|
|
1063
|
+
_canvasScale = math.min(innerWidth / width, innerHeight / height);
|
|
1064
|
+
_canvasScale = maxScale > 1 && _canvasScale > maxScale ? maxScale : _canvasScale;
|
|
1065
|
+
_canvas.style.width = width * _canvasScale + "px";
|
|
1066
|
+
_canvas.style.height = height * _canvasScale + "px";
|
|
1066
1067
|
}
|
|
1067
1068
|
_ctx.imageSmoothingEnabled = false;
|
|
1068
1069
|
instance.textalign("start", "top");
|
|
1069
|
-
instance.emit("resized",
|
|
1070
|
+
instance.emit("resized", _canvasScale);
|
|
1070
1071
|
}
|
|
1071
1072
|
function triggerEvent(eventName, arg1, arg2, arg3, arg4) {
|
|
1072
1073
|
if (!_eventListeners[eventName]) return;
|
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=2*n.PI,o=requestAnimationFrame,r=[],s=(e,t,a)=>{e.addEventListener(t,a,!1),r.push(()=>e.removeEventListener(t,a,!1))},f=(a=new AudioContext,l.zzfxV=1,(e=1,t=.05,n=220,i=0,o=0,r=.1,s=0,f=1,d=0,c=0,
|
|
1
|
+
(()=>{var e=["#211e20","#555568","#a0a08b","#e9efec"];window.litecanvas=function(t={}){let a,l=window,n=Math,i=2*n.PI,o=requestAnimationFrame,r=[],s=(e,t,a)=>{e.addEventListener(t,a,!1),r.push(()=>e.removeEventListener(t,a,!1))},f=(a=new AudioContext,l.zzfxV=1,(e=1,t=.05,n=220,i=0,o=0,r=.1,s=0,f=1,d=0,c=0,p=0,u=0,h=0,g=0,m=0,v=0,w=0,x=1,y=0,b=0,k=0)=>{let z=Math,D=2*z.PI,E=d*=500*D/44100/44100,P=n*=(1-t+2*t*z.random(t=[]))*D/44100,T=0,C=0,I=0,L=1,S=0,A=0,M=0,N=k<0?-1:1,q=D*N*k*2/44100,B=z.cos(q),H=z.sin,O=H(q)/4,V=1+O,W=-2*B/V,R=(1-O)/V,F=(1+N*B)/2/V,G=-(N+B)/V,X=0,Y=0,$=0,j=0;for(i=44100*i+9,y*=44100,o*=44100,r*=44100,w*=44100,c*=500*D/85766121e6,m*=D/44100,p*=D/44100,u*=44100,h=44100*h|0,e*=.3*l.zzfxV,N=i+y+o+r+w|0;I<N;t[I++]=M*e)++A%(100*v|0)||(M=s?1<s?2<s?3<s?H(T*T):z.max(z.min(z.tan(T),1),-1):1-(2*T/D%2+2)%2:1-4*z.abs(z.round(T/D)-T/D):H(T),M=(h?1-b+b*H(D*I/h):1)*(M<0?-1:1)*z.abs(M)**f*(I<i?I/i:I<i+y?1-(I-i)/y*(1-x):I<i+y+o?x:I<N-w?(N-I-w)/r*x:0),M=w?M/2+(w>I?0:(I<N-w?1:(N-I)/w)*t[I-w|0]/2/e):M,k&&(M=j=F*X+G*(X=Y)+F*(Y=M)-R*$-W*($=j))),T+=(q=(n+=d+=c)*z.cos(m*C++))+q*g*H(I**5),L&&++L>u&&(n+=p,P+=p,L=0),!h||++S%h||(n=P,d=E,L=L||1);(e=a.createBuffer(1,N,44100)).getChannelData(0).set(t),(n=a.createBufferSource()).buffer=e,n.connect(a.destination),n.start()});t=Object.assign({width:null,height:null,autoscale:!0,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0},t);let d=!1,c=!0,p,u=1,h,g=.5,m=1,v,w=1e3/60,x,y,b=3,k="sans-serif",z=20,D=1.2,E=Date.now(),P=e,T=[],C=[.5,0,1750,,,.3,1,,,,600,.1],I={},L={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:i,HALF_PI:i/4,lerp:(e,t,a)=>e+a*(t-e),deg2rad:e=>n.PI/180*e,rad2deg:e=>180/n.PI*e,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?L.clamp(o,l,n):o},norm:(e,t,a)=>L.map(e,t,a,0,1),rand:(e=0,t=1)=>(E=(1664525*E+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>n.floor(L.rand(e,t+1)),rseed(e){E=~~e},cls(e){null==e?h.clearRect(0,0,h.canvas.width,h.canvas.height):L.rectfill(0,0,h.canvas.width,h.canvas.height,e)},rect(e,t,a,l,n,i){h.beginPath(),h[i?"roundRect":"rect"](~~e-g,~~t-g,~~a+2*g,~~l+2*g,i),L.stroke(n)},rectfill(e,t,a,l,n,i){h.beginPath(),h[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),L.fill(n)},circ(e,t,a,l){h.beginPath(),h.arc(~~e,~~t,~~a,0,i),L.stroke(l)},circfill(e,t,a,l){h.beginPath(),h.arc(~~e,~~t,~~a,0,i),L.fill(l)},oval(e,t,a,l,n){h.beginPath(),h.ellipse(~~e,~~t,~~a,~~l,0,0,i),L.stroke(n)},ovalfill(e,t,a,l,n){h.beginPath(),h.ellipse(~~e,~~t,~~a,~~l,0,0,i),L.fill(n)},shape(e){h.beginPath();for(let t=0;t<e.length;t+=2)0===t?h.moveTo(~~e[t],~~e[t+1]):h.lineTo(~~e[t],~~e[t+1]);h.lineTo(~~e[0],~~e[1])},line(e,t,a,l,n){h.beginPath();let i=.5*(0!==g&&~~e==~~a),o=.5*(0!==g&&~~t==~~l);h.moveTo(~~e+i,~~t+o),h.lineTo(~~a+i,~~l+o),L.stroke(n)},linewidth(e){h.lineWidth=~~e,g=.5*(0!=~~e%2)},linedash(e,t=0){h.setLineDash(e),h.lineDashOffset=t},text(e,t,a,l=b,n="normal"){h.font=`${n} ${z}px ${k}`,h.fillStyle=q(l);let i=(""+a).split("\n");for(let a=0;a<i.length;a++)h.fillText(i[a],~~e,~~t+z*D*a)},textgap(e){D=e},textfont(e){k=e},textsize(e){z=e},textalign(e,t){e&&(h.textAlign=e),t&&(h.textBaseline=t)},image(e,t,a){h.drawImage(a,~~e,~~t)},spr(e,t,a){let l=a.trim().split("\n");for(let a=0;a<l.length;a++){let n=l[a].trim();for(let l=0;l<n.length;l++){let i=n[l];"."!==i&&" "!==i&&L.rectfill(e+l,t+a,1,1,parseInt(i,36)||0)}}},paint(e,t,a,l={}){let n=l.canvas||new OffscreenCanvas(1,1),i=l.scale||1,o=h;return n.width=e*i,n.height=t*i,(h=n.getContext("2d")).scale(i,i),a(h),h=o,n.transferToImageBitmap()},ctx:e=>(e&&(h=e),h),push(){h.save()},pop(){h.restore()},translate(e,t){h.translate(~~e,~~t)},scale(e,t){h.scale(e,t||e)},rotate(e){h.rotate(e)},alpha(e){h.globalAlpha=L.clamp(e,0,1)},fill(e){h.fillStyle=q(e),h.fill()},stroke(e){h.strokeStyle=q(e),h.stroke()},clip(e){h.beginPath(),e(h),h.clip()},sfx:(e,t=0,a=1)=>!!l.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||C,(0!==t||1!==a)&&((e=e.slice())[0]=a*(e[0]||1),e[10]=~~e[10]+t),f.apply(0,e),e),volume(e){l.zzfxV=e},canvas:()=>p,use(e,t={}){var a=e,l=t;let n=a(L,l);for(let e in n)L.def(e,n[e])},listen:(e,t)=>(I[e=e.toLowerCase()]=I[e]||new Set,I[e].add(t),()=>I[e]?.delete(t)),emit(e,t,a,l,n){d&&(N("before:"+(e=e.toLowerCase()),t,a,l,n),N(e,t,a,l,n),N("after:"+e,t,a,l,n))},pal(t,a=3){P=t||e,T=[],b=a},palc(e,t){null==e?T=[]:T[e]=t},def(e,a){L[e]=a,t.global&&(l[e]=a)},timescale(e){m=e},framerate(e){w=1e3/~~e},stat(e){let a={index:e,value:[t,d,w/1e3,u,I,P,C,m,l.zzfxV,E,z,k,T,D][e]};return L.emit("stat",a),a.value},pause(){c=!0,cancelAnimationFrame(y)},resume(){d&&c&&(c=!1,x=w,v=Date.now(),y=o(A))},paused:()=>c,quit(){for(let e of(L.emit("quit"),L.pause(),d=!1,I={},r))e();if(t.global){for(let e in L)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(","))L[e]=n[e];function S(){if(t.autoscale&&s(l,"resize",M),t.tapEvents){let e=e=>[(e.pageX-p.offsetLeft)/u,(e.pageY-p.offsetTop)/u],t=new Map,a=(e,a,l)=>{let n={x:a,y:l,xi:a,yi:l,t:Date.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&&Date.now()-e.t<=300,o=!1;s(p,"mousedown",t=>{if(0===t.button){t.preventDefault();let[l,n]=e(t);L.emit("tap",l,n,0),a(0,l,n),o=!0}}),s(p,"mouseup",a=>{if(0===a.button){a.preventDefault();let l=t.get(0),[n,r]=e(a);i(l)&&L.emit("tapped",l.xi,l.yi,0),L.emit("untap",n,r,0),t.delete(0),o=!1}}),s(l,"mousemove",t=>{t.preventDefault();let[a,l]=e(t);L.def("MX",a),L.def("MY",l),o&&(L.emit("tapping",a,l,0),n(0,a,l))}),s(p,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l);L.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),s(p,"touchmove",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,l]=e(a);L.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let r=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)&&L.emit("tapped",l.xi,l.yi,e),L.emit("untap",l.x,l.y,e),t.delete(e))};s(p,"touchend",r),s(p,"touchcancel",r),s(l,"blur",()=>{for(let[e,a]of(o=!1,t))L.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="";s(l,"keydown",a=>{let l=a.key.toLowerCase();e.has(l)||(e.add(l),t.add(l),n=" "===l?"space":l)}),s(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),s(l,"blur",()=>e.clear()),L.listen("after:update",()=>t.clear()),L.def("iskeydown",t=>a(e,t)),L.def("iskeypressed",e=>a(t,e)),L.def("lastkey",()=>n)}d=!0,L.resume(),L.emit("init",L)}function A(){y=o(A);let e=Date.now(),t=0,a=e-v;for(v=e,x+=a<100?a:w;x>=w;){t++,x-=w;let e=w/1e3*m;L.emit("update",e,t),L.def("T",L.T+e)}t&&(L.emit("draw",h),t>1&&(x=0))}function M(){let e=t.width>0?t.width:innerWidth,a=t.width>0?t.height||t.width:innerHeight;if(L.def("W",e),L.def("H",a),p.width=e,p.height=a,t.autoscale){let l=+t.autoscale;p.style.display||(p.style.display="block",p.style.margin="auto"),u=n.min(innerWidth/e,innerHeight/a),u=l>1&&u>l?l:u,p.style.width=e*u+"px",p.style.height=a*u+"px"}h.imageSmoothingEnabled=!1,L.textalign("start","top"),L.emit("resized",u)}function N(e,t,a,l,n){if(I[e])for(let i of I[e])i(t,a,l,n)}function q(e){return P[~~(T[e]??e)%P.length]}if(t.global){if(l.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(l,L),l.ENGINE=L}h=(p=(p="string"==typeof t.canvas?document.querySelector(t.canvas):t.canvas)||document.createElement("canvas")).getContext("2d"),s(p,"click",()=>focus()),M(),p.parentNode||document.body.appendChild(p),p.style.imageRendering="pixelated",p.oncontextmenu=()=>!1;let B=t.loop?t.loop:l;for(let e of"init,update,draw,tap,untap,tapping,tapped,resized".split(","))B[e]&&L.listen(e,B[e]);return"loading"===document.readyState?s(l,"DOMContentLoaded",()=>o(S)):y=o(S),L}})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "litecanvas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.103.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>",
|
|
@@ -31,16 +31,16 @@
|
|
|
31
31
|
"creative coding"
|
|
32
32
|
],
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@happy-dom/global-registrator": "^
|
|
35
|
-
"@size-limit/preset-small-lib": "^
|
|
36
|
-
"@swc/core": "^1.15.
|
|
34
|
+
"@happy-dom/global-registrator": "^20.7.0",
|
|
35
|
+
"@size-limit/preset-small-lib": "^12.0.0",
|
|
36
|
+
"@swc/core": "^1.15.13",
|
|
37
37
|
"ava": "^6.4.1",
|
|
38
|
-
"esbuild": "^0.
|
|
38
|
+
"esbuild": "^0.27.3",
|
|
39
39
|
"genversion": "^3.2.0",
|
|
40
40
|
"gzip-size": "^7.0.0",
|
|
41
|
-
"prettier": "^3.
|
|
41
|
+
"prettier": "^3.8.1",
|
|
42
42
|
"sinon": "^21.0.1",
|
|
43
|
-
"size-limit": "^
|
|
43
|
+
"size-limit": "^12.0.0",
|
|
44
44
|
"tap-min": "^3.0.0"
|
|
45
45
|
},
|
|
46
46
|
"trustedDependencies": [
|
package/src/index.js
CHANGED
|
@@ -53,7 +53,7 @@ export default function litecanvas(settings = {}) {
|
|
|
53
53
|
/** @type {HTMLCanvasElement} _canvas */
|
|
54
54
|
_canvas,
|
|
55
55
|
/** @type {number} */
|
|
56
|
-
|
|
56
|
+
_canvasScale = 1,
|
|
57
57
|
/** @type {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} */
|
|
58
58
|
_ctx,
|
|
59
59
|
/** @type {number} */
|
|
@@ -145,7 +145,7 @@ export default function litecanvas(settings = {}) {
|
|
|
145
145
|
DEV: assert(isNumber(end), '[litecanvas] lerp() 2nd param must be a number')
|
|
146
146
|
DEV: assert(isNumber(t), '[litecanvas] lerp() 3rd param must be a number')
|
|
147
147
|
|
|
148
|
-
return t * (end - start)
|
|
148
|
+
return start + t * (end - start)
|
|
149
149
|
},
|
|
150
150
|
|
|
151
151
|
/**
|
|
@@ -187,6 +187,7 @@ export default function litecanvas(settings = {}) {
|
|
|
187
187
|
isNumber(precision) && precision >= 0,
|
|
188
188
|
'[litecanvas] round() 2nd param must be a positive number or zero'
|
|
189
189
|
)
|
|
190
|
+
|
|
190
191
|
if (!precision) {
|
|
191
192
|
return math.round(n)
|
|
192
193
|
}
|
|
@@ -216,6 +217,24 @@ export default function litecanvas(settings = {}) {
|
|
|
216
217
|
return value
|
|
217
218
|
},
|
|
218
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Calculates the distance between a point (x1, y1) to another (x2, y2).
|
|
222
|
+
*
|
|
223
|
+
* @param {number} x1
|
|
224
|
+
* @param {number} y1
|
|
225
|
+
* @param {number} x2
|
|
226
|
+
* @param {number} y2
|
|
227
|
+
* @returns {number}
|
|
228
|
+
*/
|
|
229
|
+
dist: (x1, y1, x2, y2) => {
|
|
230
|
+
DEV: assert(isNumber(x1), '[litecanvas] dist() 1st param must be a number')
|
|
231
|
+
DEV: assert(isNumber(y1), '[litecanvas] dist() 2nd param must be a number')
|
|
232
|
+
DEV: assert(isNumber(x2), '[litecanvas] dist() 3rd param must be a number')
|
|
233
|
+
DEV: assert(isNumber(y2), '[litecanvas] dist() 4th param must be a number')
|
|
234
|
+
|
|
235
|
+
return math.hypot(x2 - x1, y2 - y1)
|
|
236
|
+
},
|
|
237
|
+
|
|
219
238
|
/**
|
|
220
239
|
* Wraps a number between `min` (inclusive) and `max` (exclusive).
|
|
221
240
|
*
|
|
@@ -285,25 +304,6 @@ export default function litecanvas(settings = {}) {
|
|
|
285
304
|
return instance.map(value, start, stop, 0, 1)
|
|
286
305
|
},
|
|
287
306
|
|
|
288
|
-
/**
|
|
289
|
-
* Interpolate between 2 values using a periodic function.
|
|
290
|
-
*
|
|
291
|
-
* @param {number} from - the lower bound
|
|
292
|
-
* @param {number} to - the higher bound
|
|
293
|
-
* @param {number} t - value passed to the periodic function
|
|
294
|
-
* @param {(n: number) => number} [fn] - the periodic function (which default to `Math.sin`)
|
|
295
|
-
*/
|
|
296
|
-
wave: (from, to, t, fn = Math.sin) => {
|
|
297
|
-
DEV: assert(isNumber(from), '[litecanvas] wave() 1st param must be a number')
|
|
298
|
-
DEV: assert(isNumber(to), '[litecanvas] wave() 2nd param must be a number')
|
|
299
|
-
DEV: assert(isNumber(t), '[litecanvas] wave() 3rd param must be a number')
|
|
300
|
-
DEV: assert(
|
|
301
|
-
'function' === typeof fn,
|
|
302
|
-
'[litecanvas] wave() 4rd param must be a function (n: number) => number'
|
|
303
|
-
)
|
|
304
|
-
return from + ((fn(t) + 1) / 2) * (to - from)
|
|
305
|
-
},
|
|
306
|
-
|
|
307
307
|
/** RNG API */
|
|
308
308
|
/**
|
|
309
309
|
* Generates a pseudorandom float between min (inclusive) and max (exclusive)
|
|
@@ -341,7 +341,7 @@ export default function litecanvas(settings = {}) {
|
|
|
341
341
|
DEV: assert(isNumber(min), '[litecanvas] randi() 1st param must be a number')
|
|
342
342
|
DEV: assert(isNumber(max), '[litecanvas] randi() 2nd param must be a number')
|
|
343
343
|
DEV: assert(
|
|
344
|
-
|
|
344
|
+
min <= max,
|
|
345
345
|
'[litecanvas] randi() the 1st param must be less than the 2nd param'
|
|
346
346
|
)
|
|
347
347
|
|
|
@@ -360,6 +360,7 @@ export default function litecanvas(settings = {}) {
|
|
|
360
360
|
isNumber(value) && value >= 0,
|
|
361
361
|
'[litecanvas] rseed() 1st param must be a positive integer or zero'
|
|
362
362
|
)
|
|
363
|
+
|
|
363
364
|
_rngSeed = ~~value
|
|
364
365
|
},
|
|
365
366
|
|
|
@@ -1084,7 +1085,7 @@ export default function litecanvas(settings = {}) {
|
|
|
1084
1085
|
_eventListeners[eventName].add(callback)
|
|
1085
1086
|
|
|
1086
1087
|
// return a function to remove this event listener
|
|
1087
|
-
return () => _eventListeners
|
|
1088
|
+
return () => _eventListeners[eventName]?.delete(callback)
|
|
1088
1089
|
},
|
|
1089
1090
|
|
|
1090
1091
|
/**
|
|
@@ -1229,7 +1230,7 @@ export default function litecanvas(settings = {}) {
|
|
|
1229
1230
|
// 2
|
|
1230
1231
|
_fpsInterval / 1000,
|
|
1231
1232
|
// 3
|
|
1232
|
-
|
|
1233
|
+
_canvasScale,
|
|
1233
1234
|
// 4
|
|
1234
1235
|
_eventListeners,
|
|
1235
1236
|
// 5
|
|
@@ -1345,8 +1346,8 @@ export default function litecanvas(settings = {}) {
|
|
|
1345
1346
|
* @param {MouseEvent | Touch} ev
|
|
1346
1347
|
*/
|
|
1347
1348
|
(ev) => [
|
|
1348
|
-
(ev.pageX - _canvas.offsetLeft) /
|
|
1349
|
-
(ev.pageY - _canvas.offsetTop) /
|
|
1349
|
+
(ev.pageX - _canvas.offsetLeft) / _canvasScale,
|
|
1350
|
+
(ev.pageY - _canvas.offsetTop) / _canvasScale,
|
|
1350
1351
|
],
|
|
1351
1352
|
_taps = new Map(),
|
|
1352
1353
|
_registerTap =
|
|
@@ -1595,8 +1596,8 @@ export default function litecanvas(settings = {}) {
|
|
|
1595
1596
|
|
|
1596
1597
|
// start the engine
|
|
1597
1598
|
_initialized = true
|
|
1598
|
-
instance.emit('init', instance)
|
|
1599
1599
|
instance.resume()
|
|
1600
|
+
instance.emit('init', instance)
|
|
1600
1601
|
}
|
|
1601
1602
|
|
|
1602
1603
|
function drawFrame() {
|
|
@@ -1695,11 +1696,11 @@ export default function litecanvas(settings = {}) {
|
|
|
1695
1696
|
_canvas.style.margin = 'auto'
|
|
1696
1697
|
}
|
|
1697
1698
|
|
|
1698
|
-
|
|
1699
|
-
|
|
1699
|
+
_canvasScale = math.min(innerWidth / width, innerHeight / height)
|
|
1700
|
+
_canvasScale = maxScale > 1 && _canvasScale > maxScale ? maxScale : _canvasScale
|
|
1700
1701
|
|
|
1701
|
-
_canvas.style.width = width *
|
|
1702
|
-
_canvas.style.height = height *
|
|
1702
|
+
_canvas.style.width = width * _canvasScale + 'px'
|
|
1703
|
+
_canvas.style.height = height * _canvasScale + 'px'
|
|
1703
1704
|
}
|
|
1704
1705
|
|
|
1705
1706
|
// set canvas image rendering properties
|
|
@@ -1710,7 +1711,7 @@ export default function litecanvas(settings = {}) {
|
|
|
1710
1711
|
|
|
1711
1712
|
// trigger "resized" event
|
|
1712
1713
|
// note: not triggered before the "init" event
|
|
1713
|
-
instance.emit('resized',
|
|
1714
|
+
instance.emit('resized', _canvasScale)
|
|
1714
1715
|
}
|
|
1715
1716
|
|
|
1716
1717
|
/**
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '0.
|
|
2
|
+
export const version = '0.103.0'
|
package/types/global.d.ts
CHANGED
|
@@ -116,14 +116,15 @@ declare global {
|
|
|
116
116
|
*/
|
|
117
117
|
function norm(value: number, start: number, stop: number): number
|
|
118
118
|
/**
|
|
119
|
-
*
|
|
119
|
+
* Calculates the distance between a point (x1, y1) to another (x2, y2).
|
|
120
120
|
*
|
|
121
|
-
* @param
|
|
122
|
-
* @param
|
|
123
|
-
* @param
|
|
124
|
-
* @param
|
|
121
|
+
* @param x1
|
|
122
|
+
* @param y1
|
|
123
|
+
* @param x2
|
|
124
|
+
* @param y2
|
|
125
|
+
* @returns the distance
|
|
125
126
|
*/
|
|
126
|
-
function
|
|
127
|
+
function dist(x1: number, y1: number, x2: number, y2: number): number
|
|
127
128
|
/**
|
|
128
129
|
* Returns the sine of a number in radians
|
|
129
130
|
*/
|
package/types/types.d.ts
CHANGED
|
@@ -110,14 +110,15 @@ type LitecanvasInstance = {
|
|
|
110
110
|
*/
|
|
111
111
|
norm(value: number, start: number, stop: number): number
|
|
112
112
|
/**
|
|
113
|
-
*
|
|
113
|
+
* Calculates the distance between a point (x1, y1) to another (x2, y2).
|
|
114
114
|
*
|
|
115
|
-
* @param
|
|
116
|
-
* @param
|
|
117
|
-
* @param
|
|
118
|
-
* @param
|
|
115
|
+
* @param x1
|
|
116
|
+
* @param y1
|
|
117
|
+
* @param x2
|
|
118
|
+
* @param y2
|
|
119
|
+
* @returns the distance
|
|
119
120
|
*/
|
|
120
|
-
|
|
121
|
+
dist(x1: number, y1: number, x2: number, y2: number): number
|
|
121
122
|
/**
|
|
122
123
|
* Returns the sine of a number in radians
|
|
123
124
|
*/
|