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