litecanvas 0.94.0 → 0.95.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 +36 -39
- package/dist/dist.js +32 -38
- package/dist/dist.min.js +1 -1
- package/package.json +2 -2
- package/src/index.js +45 -46
- package/src/version.js +1 -1
- package/types/global.d.ts +7 -1
- package/types/types.d.ts +20 -13
package/dist/dist.dev.js
CHANGED
|
@@ -32,18 +32,18 @@
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
// src/version.js
|
|
35
|
-
var version = "0.
|
|
35
|
+
var version = "0.95.0";
|
|
36
36
|
|
|
37
37
|
// src/index.js
|
|
38
38
|
function litecanvas(settings = {}) {
|
|
39
39
|
const root = window, math = Math, TWO_PI = math.PI * 2, raf = requestAnimationFrame, _browserEventListeners = [], on = (elem, evt, callback) => {
|
|
40
40
|
elem.addEventListener(evt, callback, false);
|
|
41
41
|
_browserEventListeners.push(() => elem.removeEventListener(evt, callback, false));
|
|
42
|
-
}, beginPath = (c) => c.beginPath(), isNumber = Number.isFinite, zzfx = setupZzFX(root), defaults = {
|
|
42
|
+
}, preventDefault = (ev) => ev.preventDefault(), beginPath = (c) => c.beginPath(), isNumber = Number.isFinite, zzfx = setupZzFX(root), defaults = {
|
|
43
43
|
width: null,
|
|
44
44
|
height: null,
|
|
45
45
|
autoscale: true,
|
|
46
|
-
pixelart:
|
|
46
|
+
pixelart: true,
|
|
47
47
|
canvas: null,
|
|
48
48
|
global: true,
|
|
49
49
|
loop: null,
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
animate: true
|
|
53
53
|
};
|
|
54
54
|
settings = Object.assign(defaults, settings);
|
|
55
|
-
let _initialized = false, _plugins = [], _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime,
|
|
55
|
+
let _initialized = false, _plugins = [], _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _rngSeed = Date.now(), _colors = defaultPalette, _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 = {};
|
|
56
56
|
const instance = {
|
|
57
57
|
/** @type {number} */
|
|
58
58
|
W: 0,
|
|
@@ -958,7 +958,7 @@
|
|
|
958
958
|
isNumber(value) && value >= 1,
|
|
959
959
|
"[litecanvas] framerate() 1st param must be a positive number"
|
|
960
960
|
);
|
|
961
|
-
|
|
961
|
+
_fpsInterval = 1e3 / ~~value;
|
|
962
962
|
},
|
|
963
963
|
/**
|
|
964
964
|
* Returns information about that engine instance.
|
|
@@ -974,7 +974,7 @@
|
|
|
974
974
|
// 1
|
|
975
975
|
_initialized,
|
|
976
976
|
// 2
|
|
977
|
-
|
|
977
|
+
_fpsInterval / 1e3,
|
|
978
978
|
// 3
|
|
979
979
|
_scale,
|
|
980
980
|
// 4
|
|
@@ -1028,8 +1028,8 @@
|
|
|
1028
1028
|
*/
|
|
1029
1029
|
resume() {
|
|
1030
1030
|
if (_initialized && !_rafid) {
|
|
1031
|
-
_accumulated =
|
|
1032
|
-
_lastFrameTime =
|
|
1031
|
+
_accumulated = _fpsInterval;
|
|
1032
|
+
_lastFrameTime = Date.now();
|
|
1033
1033
|
_rafid = raf(drawFrame);
|
|
1034
1034
|
}
|
|
1035
1035
|
},
|
|
@@ -1085,7 +1085,7 @@
|
|
|
1085
1085
|
// initial y
|
|
1086
1086
|
yi: y,
|
|
1087
1087
|
// timestamp
|
|
1088
|
-
t:
|
|
1088
|
+
t: Date.now()
|
|
1089
1089
|
};
|
|
1090
1090
|
_taps.set(id, tap);
|
|
1091
1091
|
return tap;
|
|
@@ -1105,12 +1105,7 @@
|
|
|
1105
1105
|
/**
|
|
1106
1106
|
* @param {{t: number}} tap
|
|
1107
1107
|
*/
|
|
1108
|
-
(tap) => tap &&
|
|
1109
|
-
), preventDefault = (
|
|
1110
|
-
/**
|
|
1111
|
-
* @param {Event} ev
|
|
1112
|
-
*/
|
|
1113
|
-
(ev) => ev.preventDefault()
|
|
1108
|
+
(tap) => tap && Date.now() - tap.t <= 300
|
|
1114
1109
|
);
|
|
1115
1110
|
let _pressingMouse = false;
|
|
1116
1111
|
on(
|
|
@@ -1231,11 +1226,13 @@
|
|
|
1231
1226
|
key = key.toLowerCase();
|
|
1232
1227
|
return !key ? keySet.size > 0 : keySet.has("space" === key ? " " : key);
|
|
1233
1228
|
};
|
|
1229
|
+
let _lastKey = "";
|
|
1234
1230
|
on(root, "keydown", (event) => {
|
|
1235
1231
|
const key = event.key.toLowerCase();
|
|
1236
1232
|
if (!_keysDown.has(key)) {
|
|
1237
1233
|
_keysDown.add(key);
|
|
1238
1234
|
_keysPress.add(key);
|
|
1235
|
+
_lastKey = key === " " ? "space" : key;
|
|
1239
1236
|
}
|
|
1240
1237
|
});
|
|
1241
1238
|
on(root, "keyup", (event) => {
|
|
@@ -1246,9 +1243,6 @@
|
|
|
1246
1243
|
instance.def(
|
|
1247
1244
|
"iskeydown",
|
|
1248
1245
|
/**
|
|
1249
|
-
* Checks if a which key is pressed (down) on the keyboard.
|
|
1250
|
-
* Note: use `iskeydown()` to check for any key.
|
|
1251
|
-
*
|
|
1252
1246
|
* @param {string} [key]
|
|
1253
1247
|
* @returns {boolean}
|
|
1254
1248
|
*/
|
|
@@ -1263,9 +1257,6 @@
|
|
|
1263
1257
|
instance.def(
|
|
1264
1258
|
"iskeypressed",
|
|
1265
1259
|
/**
|
|
1266
|
-
* Checks if a which key just got pressed on the keyboard.
|
|
1267
|
-
* Note: use `iskeypressed()` to check for any key.
|
|
1268
|
-
*
|
|
1269
1260
|
* @param {string} [key]
|
|
1270
1261
|
* @returns {boolean}
|
|
1271
1262
|
*/
|
|
@@ -1277,38 +1268,44 @@
|
|
|
1277
1268
|
return keyCheck(_keysPress, key);
|
|
1278
1269
|
}
|
|
1279
1270
|
);
|
|
1271
|
+
instance.def(
|
|
1272
|
+
"lastkey",
|
|
1273
|
+
/**
|
|
1274
|
+
* @returns {string}
|
|
1275
|
+
*/
|
|
1276
|
+
() => _lastKey
|
|
1277
|
+
);
|
|
1280
1278
|
}
|
|
1281
|
-
setInterval(() => {
|
|
1282
|
-
if (_rafid) {
|
|
1283
|
-
instance.pause();
|
|
1284
|
-
instance.resume();
|
|
1285
|
-
}
|
|
1286
|
-
}, 5e3);
|
|
1287
1279
|
_initialized = true;
|
|
1288
1280
|
instance.emit("init", instance);
|
|
1289
1281
|
instance.resume();
|
|
1290
1282
|
}
|
|
1291
|
-
function drawFrame(
|
|
1283
|
+
function drawFrame() {
|
|
1292
1284
|
if (!settings.animate) {
|
|
1293
1285
|
return instance.emit("draw", _ctx);
|
|
1294
|
-
} else if (_rafid) {
|
|
1295
|
-
_rafid = raf(drawFrame);
|
|
1296
1286
|
}
|
|
1287
|
+
let now = Date.now();
|
|
1297
1288
|
let updated = 0;
|
|
1298
|
-
let frameTime =
|
|
1289
|
+
let frameTime = now - _lastFrameTime;
|
|
1299
1290
|
_lastFrameTime = now;
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
}
|
|
1291
|
+
_accumulated += frameTime < 100 ? frameTime : _fpsInterval;
|
|
1292
|
+
while (_accumulated >= _fpsInterval) {
|
|
1293
|
+
updated++;
|
|
1294
|
+
_accumulated -= _fpsInterval;
|
|
1295
|
+
let dt = _fpsInterval / 1e3 * _timeScale;
|
|
1296
|
+
instance.emit("update", dt, updated);
|
|
1297
|
+
instance.def("T", instance.T + dt);
|
|
1308
1298
|
}
|
|
1309
1299
|
if (updated) {
|
|
1310
1300
|
instance.emit("draw", _ctx);
|
|
1301
|
+
if (updated > 1) {
|
|
1302
|
+
_accumulated = 0;
|
|
1303
|
+
DEV: console.warn(
|
|
1304
|
+
"[litecanvas] the last frame updated " + updated + " times. This can drop the FPS if it keeps happening."
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1311
1307
|
}
|
|
1308
|
+
_rafid = raf(drawFrame);
|
|
1312
1309
|
}
|
|
1313
1310
|
function setupCanvas() {
|
|
1314
1311
|
if ("string" === typeof settings.canvas) {
|
package/dist/dist.js
CHANGED
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
const root = window, math = Math, TWO_PI = math.PI * 2, raf = requestAnimationFrame, _browserEventListeners = [], on = (elem, evt, callback) => {
|
|
32
32
|
elem.addEventListener(evt, callback, false);
|
|
33
33
|
_browserEventListeners.push(() => elem.removeEventListener(evt, callback, false));
|
|
34
|
-
}, beginPath = (c) => c.beginPath(), isNumber = Number.isFinite, zzfx = setupZzFX(root), defaults = {
|
|
34
|
+
}, preventDefault = (ev) => ev.preventDefault(), beginPath = (c) => c.beginPath(), isNumber = Number.isFinite, zzfx = setupZzFX(root), defaults = {
|
|
35
35
|
width: null,
|
|
36
36
|
height: null,
|
|
37
37
|
autoscale: true,
|
|
38
|
-
pixelart:
|
|
38
|
+
pixelart: true,
|
|
39
39
|
canvas: null,
|
|
40
40
|
global: true,
|
|
41
41
|
loop: null,
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
animate: true
|
|
45
45
|
};
|
|
46
46
|
settings = Object.assign(defaults, settings);
|
|
47
|
-
let _initialized = false, _plugins = [], _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime,
|
|
47
|
+
let _initialized = false, _plugins = [], _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _rngSeed = Date.now(), _colors = defaultPalette, _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 = {};
|
|
48
48
|
const instance = {
|
|
49
49
|
/** @type {number} */
|
|
50
50
|
W: 0,
|
|
@@ -663,7 +663,7 @@
|
|
|
663
663
|
* @param {number} value
|
|
664
664
|
*/
|
|
665
665
|
framerate(value) {
|
|
666
|
-
|
|
666
|
+
_fpsInterval = 1e3 / ~~value;
|
|
667
667
|
},
|
|
668
668
|
/**
|
|
669
669
|
* Returns information about that engine instance.
|
|
@@ -678,7 +678,7 @@
|
|
|
678
678
|
// 1
|
|
679
679
|
_initialized,
|
|
680
680
|
// 2
|
|
681
|
-
|
|
681
|
+
_fpsInterval / 1e3,
|
|
682
682
|
// 3
|
|
683
683
|
_scale,
|
|
684
684
|
// 4
|
|
@@ -732,8 +732,8 @@
|
|
|
732
732
|
*/
|
|
733
733
|
resume() {
|
|
734
734
|
if (_initialized && !_rafid) {
|
|
735
|
-
_accumulated =
|
|
736
|
-
_lastFrameTime =
|
|
735
|
+
_accumulated = _fpsInterval;
|
|
736
|
+
_lastFrameTime = Date.now();
|
|
737
737
|
_rafid = raf(drawFrame);
|
|
738
738
|
}
|
|
739
739
|
},
|
|
@@ -786,7 +786,7 @@
|
|
|
786
786
|
// initial y
|
|
787
787
|
yi: y,
|
|
788
788
|
// timestamp
|
|
789
|
-
t:
|
|
789
|
+
t: Date.now()
|
|
790
790
|
};
|
|
791
791
|
_taps.set(id, tap);
|
|
792
792
|
return tap;
|
|
@@ -806,12 +806,7 @@
|
|
|
806
806
|
/**
|
|
807
807
|
* @param {{t: number}} tap
|
|
808
808
|
*/
|
|
809
|
-
(tap) => tap &&
|
|
810
|
-
), preventDefault = (
|
|
811
|
-
/**
|
|
812
|
-
* @param {Event} ev
|
|
813
|
-
*/
|
|
814
|
-
(ev) => ev.preventDefault()
|
|
809
|
+
(tap) => tap && Date.now() - tap.t <= 300
|
|
815
810
|
);
|
|
816
811
|
let _pressingMouse = false;
|
|
817
812
|
on(
|
|
@@ -932,11 +927,13 @@
|
|
|
932
927
|
key = key.toLowerCase();
|
|
933
928
|
return !key ? keySet.size > 0 : keySet.has("space" === key ? " " : key);
|
|
934
929
|
};
|
|
930
|
+
let _lastKey = "";
|
|
935
931
|
on(root, "keydown", (event) => {
|
|
936
932
|
const key = event.key.toLowerCase();
|
|
937
933
|
if (!_keysDown.has(key)) {
|
|
938
934
|
_keysDown.add(key);
|
|
939
935
|
_keysPress.add(key);
|
|
936
|
+
_lastKey = key === " " ? "space" : key;
|
|
940
937
|
}
|
|
941
938
|
});
|
|
942
939
|
on(root, "keyup", (event) => {
|
|
@@ -947,9 +944,6 @@
|
|
|
947
944
|
instance.def(
|
|
948
945
|
"iskeydown",
|
|
949
946
|
/**
|
|
950
|
-
* Checks if a which key is pressed (down) on the keyboard.
|
|
951
|
-
* Note: use `iskeydown()` to check for any key.
|
|
952
|
-
*
|
|
953
947
|
* @param {string} [key]
|
|
954
948
|
* @returns {boolean}
|
|
955
949
|
*/
|
|
@@ -960,9 +954,6 @@
|
|
|
960
954
|
instance.def(
|
|
961
955
|
"iskeypressed",
|
|
962
956
|
/**
|
|
963
|
-
* Checks if a which key just got pressed on the keyboard.
|
|
964
|
-
* Note: use `iskeypressed()` to check for any key.
|
|
965
|
-
*
|
|
966
957
|
* @param {string} [key]
|
|
967
958
|
* @returns {boolean}
|
|
968
959
|
*/
|
|
@@ -970,38 +961,41 @@
|
|
|
970
961
|
return keyCheck(_keysPress, key);
|
|
971
962
|
}
|
|
972
963
|
);
|
|
964
|
+
instance.def(
|
|
965
|
+
"lastkey",
|
|
966
|
+
/**
|
|
967
|
+
* @returns {string}
|
|
968
|
+
*/
|
|
969
|
+
() => _lastKey
|
|
970
|
+
);
|
|
973
971
|
}
|
|
974
|
-
setInterval(() => {
|
|
975
|
-
if (_rafid) {
|
|
976
|
-
instance.pause();
|
|
977
|
-
instance.resume();
|
|
978
|
-
}
|
|
979
|
-
}, 5e3);
|
|
980
972
|
_initialized = true;
|
|
981
973
|
instance.emit("init", instance);
|
|
982
974
|
instance.resume();
|
|
983
975
|
}
|
|
984
|
-
function drawFrame(
|
|
976
|
+
function drawFrame() {
|
|
985
977
|
if (!settings.animate) {
|
|
986
978
|
return instance.emit("draw", _ctx);
|
|
987
|
-
} else if (_rafid) {
|
|
988
|
-
_rafid = raf(drawFrame);
|
|
989
979
|
}
|
|
980
|
+
let now = Date.now();
|
|
990
981
|
let updated = 0;
|
|
991
|
-
let frameTime =
|
|
982
|
+
let frameTime = now - _lastFrameTime;
|
|
992
983
|
_lastFrameTime = now;
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
}
|
|
984
|
+
_accumulated += frameTime < 100 ? frameTime : _fpsInterval;
|
|
985
|
+
while (_accumulated >= _fpsInterval) {
|
|
986
|
+
updated++;
|
|
987
|
+
_accumulated -= _fpsInterval;
|
|
988
|
+
let dt = _fpsInterval / 1e3 * _timeScale;
|
|
989
|
+
instance.emit("update", dt, updated);
|
|
990
|
+
instance.def("T", instance.T + dt);
|
|
1001
991
|
}
|
|
1002
992
|
if (updated) {
|
|
1003
993
|
instance.emit("draw", _ctx);
|
|
994
|
+
if (updated > 1) {
|
|
995
|
+
_accumulated = 0;
|
|
996
|
+
}
|
|
1004
997
|
}
|
|
998
|
+
_rafid = raf(drawFrame);
|
|
1005
999
|
}
|
|
1006
1000
|
function setupCanvas() {
|
|
1007
1001
|
if ("string" === typeof settings.canvas) {
|
package/dist/dist.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{var e=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(t={}){let a=window,i=Math,l=2*i.PI,n=requestAnimationFrame,o=[],r=(e,t,a)=>{e.addEventListener(t,a,!1),o.push(()=>e.removeEventListener(t,a,!1))},s=e=>e.
|
|
1
|
+
(()=>{var e=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(t={}){let a=window,i=Math,l=2*i.PI,n=requestAnimationFrame,o=[],r=(e,t,a)=>{e.addEventListener(t,a,!1),o.push(()=>e.removeEventListener(t,a,!1))},s=e=>e.preventDefault(),f=e=>e.beginPath(),c=(e=>{let t=new AudioContext;return e.zzfxV=1,(a=1,i=.05,l=220,n=0,o=0,r=.1,s=0,f=1,c=0,d=0,u=0,p=0,h=0,m=0,g=0,w=0,v=0,x=1,y=0,b=0,k=0)=>{let E=Math,z=2*E.PI,T=c*=500*z/44100/44100,C=l*=(1-i+2*i*E.random(i=[]))*z/44100,I=0,A=0,L=0,S=1,D=0,M=0,N=0,P=k<0?-1:1,F=z*P*k*2/44100,q=E.cos(F),B=E.sin,H=B(F)/4,O=1+H,V=-2*q/O,W=(1-H)/O,R=(1+P*q)/2/O,G=-(P+q)/O,X=0,Y=0,$=0,j=0;for(n=44100*n+9,y*=44100,o*=44100,r*=44100,v*=44100,d*=500*z/85766121e6,g*=z/44100,u*=z/44100,p*=44100,h=44100*h|0,a*=.3*e.zzfxV,P=n+y+o+r+v|0;L<P;i[L++]=N*a)++M%(100*w|0)||(N=s?1<s?2<s?3<s?B(I*I):E.max(E.min(E.tan(I),1),-1):1-(2*I/z%2+2)%2:1-4*E.abs(E.round(I/z)-I/z):B(I),N=(h?1-b+b*B(z*L/h):1)*(N<0?-1:1)*E.abs(N)**f*(L<n?L/n:L<n+y?1-(L-n)/y*(1-x):L<n+y+o?x:L<P-v?(P-L-v)/r*x:0),N=v?N/2+(v>L?0:(L<P-v?1:(P-L)/v)*i[L-v|0]/2/a):N,k&&(N=j=R*X+G*(X=Y)+R*(Y=N)-W*$-V*($=j))),I+=(F=(l+=c+=d)*E.cos(g*A++))+F*m*B(L**5),S&&++S>p&&(l+=u,C+=u,S=0),!h||++D%h||(l=C,c=T,S=S||1);(a=t.createBuffer(1,P,44100)).getChannelData(0).set(i),(l=t.createBufferSource()).buffer=a,l.connect(t.destination),l.start()}})(a);t=Object.assign({width:null,height:null,autoscale:!0,pixelart:!0,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0,animate:!0},t);let d=!1,u=[],p,h=1,m,g=.5,w=1,v,x=1e3/60,y,b,k="sans-serif",E=20,z=Date.now(),T=e,C=[.5,0,1750,,,.3,1,,,,600,.1],I={},A={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:l,HALF_PI:l/4,lerp:(e,t,a)=>a*(t-e)+e,deg2rad:e=>i.PI/180*e,rad2deg:e=>180/i.PI*e,round:(e,t=0)=>{if(!t)return i.round(e);let a=10**t;return i.round(e*a)/a},clamp:(e,t,a)=>e<t?t:e>a?a:e,wrap:(e,t,a)=>e-(a-t)*i.floor((e-t)/(a-t)),map(e,t,a,i,l,n){let o=(e-t)/(a-t)*(l-i)+i;return n?A.clamp(o,i,l):o},norm:(e,t,a)=>A.map(e,t,a,0,1),wave:(e,t,a,i=Math.sin)=>e+(i(a)+1)/2*(t-e),rand:(e=0,t=1)=>(z=(1664525*z+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>i.floor(A.rand(e,t+1)),rseed(e){z=~~e},cls(e){null==e?m.clearRect(0,0,m.canvas.width,m.canvas.height):A.rectfill(0,0,m.canvas.width,m.canvas.height,e)},rect(e,t,a,i,l,n){f(m),m[n?"roundRect":"rect"](~~e-g,~~t-g,~~a+2*g,~~i+2*g,n),A.stroke(l)},rectfill(e,t,a,i,l,n){f(m),m[n?"roundRect":"rect"](~~e,~~t,~~a,~~i,n),A.fill(l)},circ(e,t,a,i){f(m),m.arc(~~e,~~t,~~a,0,l),A.stroke(i)},circfill(e,t,a,i){f(m),m.arc(~~e,~~t,~~a,0,l),A.fill(i)},oval(e,t,a,i,n){f(m),m.ellipse(~~e,~~t,~~a,~~i,0,0,l),A.stroke(n)},ovalfill(e,t,a,i,n){f(m),m.ellipse(~~e,~~t,~~a,~~i,0,0,l),A.fill(n)},line(e,t,a,i,l){f(m);let n=.5*(0!==g&&~~e==~~a),o=.5*(0!==g&&~~t==~~i);m.moveTo(~~e+n,~~t+o),m.lineTo(~~a+n,~~i+o),A.stroke(l)},linewidth(e){m.lineWidth=~~e,g=.5*(0!=~~e%2)},linedash(e,t=0){m.setLineDash(e),m.lineDashOffset=t},text(e,t,a,i=3,l="normal"){m.font=`${l} ${E}px ${k}`,m.fillStyle=T[~~i%T.length],m.fillText(a,~~e,~~t)},textfont(e){k=e},textsize(e){E=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,i={}){let l=i.canvas||new OffscreenCanvas(1,1),n=i.scale||1,o=m;if(l.width=e*n,l.height=t*n,(m=l.getContext("2d")).scale(n,n),Array.isArray(a)){let e=0,t=0;for(let i of(m.imageSmoothingEnabled=!1,a)){for(let a of i)" "!==a&&"."!==a&&A.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(m);return m=o,l.transferToImageBitmap()},ctx:e=>(e&&(m=e),m),push:()=>m.save(),pop:()=>m.restore(),translate:(e,t)=>m.translate(~~e,~~t),scale:(e,t)=>m.scale(e,t||e),rotate:e=>m.rotate(e),alpha(e){m.globalAlpha=A.clamp(e,0,1)},fill(e){m.fillStyle=T[~~e%T.length],m.fill()},stroke(e){m.strokeStyle=T[~~e%T.length],m.stroke()},clip(e){f(m),e(m),m.clip()},sfx:(e,t=0,i=1)=>!!a.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||C,(0!==t||1!==i)&&((e=e.slice())[0]=i*(e[0]||1),e[10]=~~e[10]+t),c.apply(0,e),e),volume(e){a.zzfxV=e},canvas:()=>p,use(e,t={}){d?N(e,t):u.push([e,t])},listen:(e,t)=>(I[e=e.toLowerCase()]=I[e]||new Set,I[e].add(t),()=>I&&I[e].delete(t)),emit(e,t,a,i,l){d&&(M("before:"+(e=e.toLowerCase()),t,a,i,l),M(e,t,a,i,l),M("after:"+e,t,a,i,l))},pal(t=e){T=t},def(e,i){A[e]=i,t.global&&(a[e]=i)},timescale(e){w=e},framerate(e){x=1e3/~~e},stat(e){let i={index:e,value:[t,d,x/1e3,h,I,T,C,w,a.zzfxV,z,E,k][e]};return A.emit("stat",i),i.value},quit(){for(let e of(A.pause(),A.emit("quit"),I={},o))e();if(t.global){for(let e in A)delete a[e];delete a.ENGINE}d=!1},pause(){cancelAnimationFrame(b),b=0},resume(){d&&!b&&(y=x,v=Date.now(),b=n(S))},paused:()=>!b};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))A[e]=i[e];function L(){let e=t.loop?t.loop:a;for(let t of"init,update,draw,tap,untap,tapping,tapped,resized".split(","))e[t]&&A.listen(t,e[t]);for(let[e,t]of u)N(e,t);if(t.autoscale&&r(a,"resize",D),t.tapEvents){let e=e=>[(e.pageX-p.offsetLeft)/h,(e.pageY-p.offsetTop)/h],t=new Map,i=(e,a,i)=>{let l={x:a,y:i,xi:a,yi:i,t:Date.now()};return t.set(e,l),l},l=(e,a,l)=>{let n=t.get(e)||i(e);n.x=a,n.y=l},n=e=>e&&Date.now()-e.t<=300,o=!1;r(p,"mousedown",t=>{if(0===t.button){s(t);let[a,l]=e(t);A.emit("tap",a,l,0),i(0,a,l),o=!0}}),r(p,"mouseup",a=>{if(0===a.button){s(a);let i=t.get(0),[l,r]=e(a);n(i)&&A.emit("tapped",i.xi,i.yi,0),A.emit("untap",l,r,0),t.delete(0),o=!1}}),r(a,"mousemove",t=>{s(t);let[a,i]=e(t);A.def("MX",a),A.def("MY",i),o&&(A.emit("tapping",a,i,0),l(0,a,i))}),r(p,"touchstart",t=>{for(let a of(s(t),t.changedTouches)){let[t,l]=e(a);A.emit("tap",t,l,a.identifier+1),i(a.identifier+1,t,l)}}),r(p,"touchmove",t=>{for(let a of(s(t),t.changedTouches)){let[t,i]=e(a);A.emit("tapping",t,i,a.identifier+1),l(a.identifier+1,t,i)}});let f=e=>{s(e);let a=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,i]of t)a.includes(e)||(n(i)&&A.emit("tapped",i.xi,i.yi,e),A.emit("untap",i.x,i.y,e),t.delete(e))};r(p,"touchend",f),r(p,"touchcancel",f),r(a,"blur",()=>{for(let[e,a]of(o=!1,t))A.emit("untap",a.x,a.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,i=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0,l="";r(a,"keydown",a=>{let i=a.key.toLowerCase();e.has(i)||(e.add(i),t.add(i),l=" "===i?"space":i)}),r(a,"keyup",t=>{e.delete(t.key.toLowerCase())}),r(a,"blur",()=>e.clear()),A.listen("after:update",()=>t.clear()),A.def("iskeydown",t=>i(e,t)),A.def("iskeypressed",e=>i(t,e)),A.def("lastkey",()=>l)}d=!0,A.emit("init",A),A.resume()}function S(){if(!t.animate)return A.emit("draw",m);let e=Date.now(),a=0,i=e-v;for(v=e,y+=i<100?i:x;y>=x;){a++,y-=x;let e=x/1e3*w;A.emit("update",e,a),A.def("T",A.T+e)}a&&(A.emit("draw",m),a>1&&(y=0)),b=n(S)}function D(){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),p.width=e,p.height=a,t.autoscale){let l=+t.autoscale;p.style.display||(p.style.display="block",p.style.margin="auto"),h=i.min(innerWidth/e,innerHeight/a),h=l>1&&h>l?l:h,p.style.width=e*h+"px",p.style.height=a*h+"px"}t.pixelart&&(m.imageSmoothingEnabled=!1,p.style.imageRendering="pixelated"),A.textalign("start","top"),A.emit("resized",h),t.animate||n(S)}function M(e,t,a,i,l){if(I[e])for(let n of I[e])n(t,a,i,l)}function N(e,t){let a=e(A,t);for(let e in a)A.def(e,a[e])}if(t.global){if(a.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(a,A),a.ENGINE=A}return m=(p=(p="string"==typeof t.canvas?document.querySelector(t.canvas):t.canvas)||document.createElement("canvas")).getContext("2d"),r(p,"click",()=>focus()),p.style="",D(),p.parentNode||document.body.appendChild(p),p.oncontextmenu=()=>!1,"loading"===document.readyState?r(a,"DOMContentLoaded",()=>n(L)):n(L),A}})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "litecanvas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.95.0",
|
|
4
4
|
"description": "Lightweight HTML5 canvas 2D 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>",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@litecanvas/jsdom-extras": "^2.0.1",
|
|
35
35
|
"@size-limit/preset-small-lib": "^11.2.0",
|
|
36
|
-
"@swc/core": "^1.13.
|
|
36
|
+
"@swc/core": "^1.13.2",
|
|
37
37
|
"@types/jsdom": "^21.1.7",
|
|
38
38
|
"ava": "^6.4.1",
|
|
39
39
|
"esbuild": "^0.25.8",
|
package/src/index.js
CHANGED
|
@@ -23,6 +23,8 @@ export default function litecanvas(settings = {}) {
|
|
|
23
23
|
elem.addEventListener(evt, callback, false)
|
|
24
24
|
_browserEventListeners.push(() => elem.removeEventListener(evt, callback, false))
|
|
25
25
|
},
|
|
26
|
+
/** @type {(ev: Event) => void} */
|
|
27
|
+
preventDefault = (ev) => ev.preventDefault(),
|
|
26
28
|
/** @type {(c: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D) => void} */
|
|
27
29
|
beginPath = (c) => c.beginPath(),
|
|
28
30
|
isNumber = Number.isFinite,
|
|
@@ -32,7 +34,7 @@ export default function litecanvas(settings = {}) {
|
|
|
32
34
|
width: null,
|
|
33
35
|
height: null,
|
|
34
36
|
autoscale: true,
|
|
35
|
-
pixelart:
|
|
37
|
+
pixelart: true,
|
|
36
38
|
canvas: null,
|
|
37
39
|
global: true,
|
|
38
40
|
loop: null,
|
|
@@ -61,7 +63,7 @@ export default function litecanvas(settings = {}) {
|
|
|
61
63
|
/** @type {number} */
|
|
62
64
|
_lastFrameTime,
|
|
63
65
|
/** @type {number} duration of a frame at 60 FPS (default) */
|
|
64
|
-
|
|
66
|
+
_fpsInterval = 1000 / 60,
|
|
65
67
|
/** @type {number} */
|
|
66
68
|
_accumulated,
|
|
67
69
|
/** @type {number?} */
|
|
@@ -1120,7 +1122,7 @@ export default function litecanvas(settings = {}) {
|
|
|
1120
1122
|
'[litecanvas] framerate() 1st param must be a positive number'
|
|
1121
1123
|
)
|
|
1122
1124
|
|
|
1123
|
-
|
|
1125
|
+
_fpsInterval = 1000 / ~~value
|
|
1124
1126
|
},
|
|
1125
1127
|
|
|
1126
1128
|
/**
|
|
@@ -1138,7 +1140,7 @@ export default function litecanvas(settings = {}) {
|
|
|
1138
1140
|
// 1
|
|
1139
1141
|
_initialized,
|
|
1140
1142
|
// 2
|
|
1141
|
-
|
|
1143
|
+
_fpsInterval / 1000,
|
|
1142
1144
|
// 3
|
|
1143
1145
|
_scale,
|
|
1144
1146
|
// 4
|
|
@@ -1210,8 +1212,8 @@ export default function litecanvas(settings = {}) {
|
|
|
1210
1212
|
*/
|
|
1211
1213
|
resume() {
|
|
1212
1214
|
if (_initialized && !_rafid) {
|
|
1213
|
-
_accumulated =
|
|
1214
|
-
_lastFrameTime =
|
|
1215
|
+
_accumulated = _fpsInterval
|
|
1216
|
+
_lastFrameTime = Date.now()
|
|
1215
1217
|
_rafid = raf(drawFrame)
|
|
1216
1218
|
}
|
|
1217
1219
|
},
|
|
@@ -1280,7 +1282,7 @@ export default function litecanvas(settings = {}) {
|
|
|
1280
1282
|
// initial y
|
|
1281
1283
|
yi: y,
|
|
1282
1284
|
// timestamp
|
|
1283
|
-
t:
|
|
1285
|
+
t: Date.now(),
|
|
1284
1286
|
}
|
|
1285
1287
|
_taps.set(id, tap)
|
|
1286
1288
|
return tap
|
|
@@ -1300,12 +1302,7 @@ export default function litecanvas(settings = {}) {
|
|
|
1300
1302
|
/**
|
|
1301
1303
|
* @param {{t: number}} tap
|
|
1302
1304
|
*/
|
|
1303
|
-
(tap) => tap &&
|
|
1304
|
-
preventDefault =
|
|
1305
|
-
/**
|
|
1306
|
-
* @param {Event} ev
|
|
1307
|
-
*/
|
|
1308
|
-
(ev) => ev.preventDefault()
|
|
1305
|
+
(tap) => tap && Date.now() - tap.t <= 300
|
|
1309
1306
|
|
|
1310
1307
|
let _pressingMouse = false
|
|
1311
1308
|
|
|
@@ -1454,11 +1451,15 @@ export default function litecanvas(settings = {}) {
|
|
|
1454
1451
|
return !key ? keySet.size > 0 : keySet.has('space' === key ? ' ' : key)
|
|
1455
1452
|
}
|
|
1456
1453
|
|
|
1454
|
+
/** @type {string} */
|
|
1455
|
+
let _lastKey = ''
|
|
1456
|
+
|
|
1457
1457
|
on(root, 'keydown', (/** @type {KeyboardEvent} */ event) => {
|
|
1458
1458
|
const key = event.key.toLowerCase()
|
|
1459
1459
|
if (!_keysDown.has(key)) {
|
|
1460
1460
|
_keysDown.add(key)
|
|
1461
1461
|
_keysPress.add(key)
|
|
1462
|
+
_lastKey = key === ' ' ? 'space' : key
|
|
1462
1463
|
}
|
|
1463
1464
|
})
|
|
1464
1465
|
|
|
@@ -1472,9 +1473,6 @@ export default function litecanvas(settings = {}) {
|
|
|
1472
1473
|
instance.def(
|
|
1473
1474
|
'iskeydown',
|
|
1474
1475
|
/**
|
|
1475
|
-
* Checks if a which key is pressed (down) on the keyboard.
|
|
1476
|
-
* Note: use `iskeydown()` to check for any key.
|
|
1477
|
-
*
|
|
1478
1476
|
* @param {string} [key]
|
|
1479
1477
|
* @returns {boolean}
|
|
1480
1478
|
*/
|
|
@@ -1490,9 +1488,6 @@ export default function litecanvas(settings = {}) {
|
|
|
1490
1488
|
instance.def(
|
|
1491
1489
|
'iskeypressed',
|
|
1492
1490
|
/**
|
|
1493
|
-
* Checks if a which key just got pressed on the keyboard.
|
|
1494
|
-
* Note: use `iskeypressed()` to check for any key.
|
|
1495
|
-
*
|
|
1496
1491
|
* @param {string} [key]
|
|
1497
1492
|
* @returns {boolean}
|
|
1498
1493
|
*/
|
|
@@ -1504,16 +1499,15 @@ export default function litecanvas(settings = {}) {
|
|
|
1504
1499
|
return keyCheck(_keysPress, key)
|
|
1505
1500
|
}
|
|
1506
1501
|
)
|
|
1507
|
-
}
|
|
1508
1502
|
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
}
|
|
1503
|
+
instance.def(
|
|
1504
|
+
'lastkey',
|
|
1505
|
+
/**
|
|
1506
|
+
* @returns {string}
|
|
1507
|
+
*/
|
|
1508
|
+
() => _lastKey
|
|
1509
|
+
)
|
|
1510
|
+
}
|
|
1517
1511
|
|
|
1518
1512
|
// start the engine
|
|
1519
1513
|
_initialized = true
|
|
@@ -1521,37 +1515,42 @@ export default function litecanvas(settings = {}) {
|
|
|
1521
1515
|
instance.resume()
|
|
1522
1516
|
}
|
|
1523
1517
|
|
|
1524
|
-
|
|
1525
|
-
* @param {DOMHighResTimeStamp} now
|
|
1526
|
-
*/
|
|
1527
|
-
function drawFrame(now) {
|
|
1518
|
+
function drawFrame() {
|
|
1528
1519
|
if (!settings.animate) {
|
|
1529
1520
|
return instance.emit('draw', _ctx)
|
|
1530
1521
|
}
|
|
1531
|
-
// request the next frame
|
|
1532
|
-
// only when the engine loop are not paused (_rafid >= 1)
|
|
1533
|
-
else if (_rafid) {
|
|
1534
|
-
_rafid = raf(drawFrame)
|
|
1535
|
-
}
|
|
1536
1522
|
|
|
1523
|
+
let now = Date.now()
|
|
1537
1524
|
let updated = 0
|
|
1538
|
-
let frameTime =
|
|
1525
|
+
let frameTime = now - _lastFrameTime
|
|
1539
1526
|
|
|
1540
1527
|
_lastFrameTime = now
|
|
1528
|
+
_accumulated += frameTime < 100 ? frameTime : _fpsInterval
|
|
1541
1529
|
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1530
|
+
while (_accumulated >= _fpsInterval) {
|
|
1531
|
+
updated++
|
|
1532
|
+
_accumulated -= _fpsInterval
|
|
1533
|
+
|
|
1534
|
+
let dt = (_fpsInterval / 1000) * _timeScale
|
|
1535
|
+
|
|
1536
|
+
instance.emit('update', dt, updated)
|
|
1537
|
+
instance.def('T', instance.T + dt)
|
|
1550
1538
|
}
|
|
1551
1539
|
|
|
1552
1540
|
if (updated) {
|
|
1553
1541
|
instance.emit('draw', _ctx)
|
|
1542
|
+
if (updated > 1) {
|
|
1543
|
+
_accumulated = 0
|
|
1544
|
+
DEV: console.warn(
|
|
1545
|
+
'[litecanvas] the last frame updated ' +
|
|
1546
|
+
updated +
|
|
1547
|
+
' times. This can drop the FPS if it keeps happening.'
|
|
1548
|
+
)
|
|
1549
|
+
}
|
|
1554
1550
|
}
|
|
1551
|
+
|
|
1552
|
+
// request the next frame
|
|
1553
|
+
_rafid = raf(drawFrame)
|
|
1555
1554
|
}
|
|
1556
1555
|
|
|
1557
1556
|
function setupCanvas() {
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '0.
|
|
2
|
+
export const version = '0.95.0'
|
package/types/global.d.ts
CHANGED
|
@@ -477,7 +477,7 @@ declare global {
|
|
|
477
477
|
*/
|
|
478
478
|
function volume(value: number): void
|
|
479
479
|
|
|
480
|
-
/**
|
|
480
|
+
/** KEYBOARD API */
|
|
481
481
|
/**
|
|
482
482
|
* Checks if a which key is pressed on the keyboard.
|
|
483
483
|
* Note: use `iskeydown()` to check for any key pressed.
|
|
@@ -494,6 +494,12 @@ declare global {
|
|
|
494
494
|
* @returns `true` if the which key was pressed
|
|
495
495
|
*/
|
|
496
496
|
function iskeypressed(key: string): boolean
|
|
497
|
+
/**
|
|
498
|
+
* Returns the last pressed.
|
|
499
|
+
*
|
|
500
|
+
* @returns {string}
|
|
501
|
+
*/
|
|
502
|
+
function lastkey(): string
|
|
497
503
|
|
|
498
504
|
/** PLUGINS API */
|
|
499
505
|
/**
|
package/types/types.d.ts
CHANGED
|
@@ -467,7 +467,7 @@ type LitecanvasInstance = {
|
|
|
467
467
|
*/
|
|
468
468
|
volume(value: number): void
|
|
469
469
|
|
|
470
|
-
/**
|
|
470
|
+
/** KEYBOARD API */
|
|
471
471
|
/**
|
|
472
472
|
* Checks if a which key is pressed on the keyboard.
|
|
473
473
|
* Note: use `iskeydown()` to check for any key pressed.
|
|
@@ -484,6 +484,12 @@ type LitecanvasInstance = {
|
|
|
484
484
|
* @returns `true` if the which key was pressed
|
|
485
485
|
*/
|
|
486
486
|
iskeypressed?(key: string): boolean
|
|
487
|
+
/**
|
|
488
|
+
* Returns the last pressed.
|
|
489
|
+
*
|
|
490
|
+
* @returns {string}
|
|
491
|
+
*/
|
|
492
|
+
lastkey?(): string
|
|
487
493
|
|
|
488
494
|
/** PLUGINS API */
|
|
489
495
|
/**
|
|
@@ -603,7 +609,7 @@ type LitecanvasOptions = {
|
|
|
603
609
|
* If `true`, the pixel art images won't look blurry.
|
|
604
610
|
* Also, disables canvas built-in antialias.
|
|
605
611
|
*
|
|
606
|
-
* Default: `
|
|
612
|
+
* Default: `true`
|
|
607
613
|
*/
|
|
608
614
|
pixelart?: boolean
|
|
609
615
|
/**
|
|
@@ -613,16 +619,17 @@ type LitecanvasOptions = {
|
|
|
613
619
|
/**
|
|
614
620
|
* Specify your game loop callbacks.
|
|
615
621
|
* By default use that global functions (if they exist):
|
|
616
|
-
* - `window.init(): void`
|
|
622
|
+
* - `window.init(instance: LitecanvasInstance): void`
|
|
617
623
|
* - `window.update(dt: number): void`
|
|
618
|
-
* - `window.draw(): void`
|
|
619
|
-
* - `window.resized(): void`
|
|
620
|
-
* - `window.tap(tapX: number, tapY: number,
|
|
621
|
-
* - `window.untap(tapX: number, tapY: number,
|
|
622
|
-
* - `window.tapped(tapX: number, tapY: number,
|
|
623
|
-
* - `window.tapping(tapX: number, tapY: number,
|
|
624
|
+
* - `window.draw(ctx: CanvasRenderingContext2D): void`
|
|
625
|
+
* - `window.resized(scale: number): void`
|
|
626
|
+
* - `window.tap(tapX: number, tapY: number, touchId: number): void`
|
|
627
|
+
* - `window.untap(tapX: number, tapY: number, touchId: number): void`
|
|
628
|
+
* - `window.tapped(tapX: number, tapY: number, touchId: number): void`
|
|
629
|
+
* - `window.tapping(tapX: number, tapY: number, touchId: number): void`
|
|
624
630
|
*/
|
|
625
631
|
loop?: LitecanvasGameLoop
|
|
632
|
+
|
|
626
633
|
/**
|
|
627
634
|
* default: `true`
|
|
628
635
|
*
|
|
@@ -652,10 +659,10 @@ type LitecanvasGameLoop = {
|
|
|
652
659
|
update?: (dt: number) => void
|
|
653
660
|
draw?: () => void
|
|
654
661
|
resized?: () => void
|
|
655
|
-
tap?: (tapX: number, tapY: number,
|
|
656
|
-
untap?: (tapX: number, tapY: number,
|
|
657
|
-
tapped?: (tapX: number, tapY: number,
|
|
658
|
-
tapping?: (tapX: number, tapY: number,
|
|
662
|
+
tap?: (tapX: number, tapY: number, touchId: number) => void
|
|
663
|
+
untap?: (tapX: number, tapY: number, touchId: number) => void
|
|
664
|
+
tapped?: (tapX: number, tapY: number, touchId: number) => void
|
|
665
|
+
tapping?: (tapX: number, tapY: number, touchId: number) => void
|
|
659
666
|
}
|
|
660
667
|
|
|
661
668
|
type drawCallback = (context: OffscreenCanvasRenderingContext2D) => void
|