litecanvas 0.95.1 → 0.97.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.js CHANGED
@@ -31,20 +31,18 @@
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
- }, preventDefault = (ev) => ev.preventDefault(), beginPath = (c) => c.beginPath(), isNumber = Number.isFinite, zzfx = setupZzFX(root), defaults = {
34
+ }, lowerCase = (str) => str.toLowerCase(), 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: true,
39
38
  canvas: null,
40
39
  global: true,
41
40
  loop: null,
42
41
  tapEvents: true,
43
- keyboardEvents: true,
44
- animate: true
42
+ keyboardEvents: true
45
43
  };
46
44
  settings = Object.assign(defaults, settings);
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 = {};
45
+ 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(), _currentPalette, _colors, _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
46
  const instance = {
49
47
  /** @type {number} */
50
48
  W: 0,
@@ -342,7 +340,7 @@
342
340
  instance.stroke(color);
343
341
  },
344
342
  /**
345
- * Sets the thickness of lines
343
+ * Sets the thickness of the lines
346
344
  *
347
345
  * @param {number} value
348
346
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineWidth
@@ -417,41 +415,46 @@
417
415
  image(x, y, source) {
418
416
  _ctx.drawImage(source, ~~x, ~~y);
419
417
  },
418
+ /**
419
+ * Draw a sprite pxiel by pixel represented by a string. Each pixel must be a base 36 number (0-9 or a-z) or a dot.
420
+ *
421
+ * @param {number} x
422
+ * @param {number} y
423
+ * @param {number} width
424
+ * @param {number} height
425
+ * @param {string} pixels
426
+ */
427
+ spr(x, y, width, height, pixels) {
428
+ const chars = pixels.replace(/\s/g, "");
429
+ for (let gridx = 0; gridx < width; gridx++) {
430
+ for (let gridy = 0; gridy < height; gridy++) {
431
+ const char = chars[height * gridy + gridx] || ".";
432
+ if (char !== ".") {
433
+ instance.rectfill(x + gridx, y + gridy, 1, 1, parseInt(char, 16) || 0);
434
+ }
435
+ }
436
+ }
437
+ },
420
438
  /**
421
439
  * Draw in an OffscreenCanvas and returns its image.
422
440
  *
423
441
  * @param {number} width
424
442
  * @param {number} height
425
- * @param {string[]|drawCallback} drawing
443
+ * @param {drawCallback} callback
426
444
  * @param {object} [options]
427
445
  * @param {number} [options.scale=1]
428
446
  * @param {OffscreenCanvas} [options.canvas]
429
447
  * @returns {ImageBitmap}
430
448
  * @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
431
449
  */
432
- paint(width, height, drawing, options = {}) {
433
- const canvas = options.canvas || new OffscreenCanvas(1, 1), scale = options.scale || 1, contextOriginal = _ctx;
450
+ paint(width, height, callback, options = {}) {
451
+ const canvas = options.canvas || new OffscreenCanvas(1, 1), scale = options.scale || 1, currentContext = _ctx;
434
452
  canvas.width = width * scale;
435
453
  canvas.height = height * scale;
436
454
  _ctx = canvas.getContext("2d");
437
455
  _ctx.scale(scale, scale);
438
- if (Array.isArray(drawing)) {
439
- let x = 0, y = 0;
440
- _ctx.imageSmoothingEnabled = false;
441
- for (const str of drawing) {
442
- for (const color of str) {
443
- if (" " !== color && "." !== color) {
444
- instance.rectfill(x, y, 1, 1, parseInt(color, 16));
445
- }
446
- x++;
447
- }
448
- y++;
449
- x = 0;
450
- }
451
- } else {
452
- drawing(_ctx);
453
- }
454
- _ctx = contextOriginal;
456
+ callback(_ctx);
457
+ _ctx = currentContext;
455
458
  return canvas.transferToImageBitmap();
456
459
  },
457
460
  /** ADVANCED GRAPHICS API */
@@ -473,21 +476,25 @@
473
476
  *
474
477
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
475
478
  */
476
- push: () => _ctx.save(),
479
+ push() {
480
+ _ctx.save();
481
+ },
477
482
  /**
478
483
  * restores the drawing style settings and transformations
479
484
  *
480
485
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore
481
486
  */
482
- pop: () => _ctx.restore(),
487
+ pop() {
488
+ _ctx.restore();
489
+ },
483
490
  /**
484
491
  * Adds a translation to the transformation matrix.
485
492
  *
486
493
  * @param {number} x
487
494
  * @param {number} y
488
495
  */
489
- translate: (x, y) => {
490
- return _ctx.translate(~~x, ~~y);
496
+ translate(x, y) {
497
+ _ctx.translate(~~x, ~~y);
491
498
  },
492
499
  /**
493
500
  * Adds a scaling transformation to the canvas units horizontally and/or vertically.
@@ -495,16 +502,16 @@
495
502
  * @param {number} x
496
503
  * @param {number} [y]
497
504
  */
498
- scale: (x, y) => {
499
- return _ctx.scale(x, y || x);
505
+ scale(x, y) {
506
+ _ctx.scale(x, y || x);
500
507
  },
501
508
  /**
502
509
  * Adds a rotation to the transformation matrix.
503
510
  *
504
511
  * @param {number} radians
505
512
  */
506
- rotate: (radians) => {
507
- return _ctx.rotate(radians);
513
+ rotate(radians) {
514
+ _ctx.rotate(radians);
508
515
  },
509
516
  /**
510
517
  * Sets the alpha (opacity) value to apply when drawing new shapes and images
@@ -605,7 +612,7 @@
605
612
  * @returns {Function} a function to remove the listener
606
613
  */
607
614
  listen(eventName, callback) {
608
- eventName = eventName.toLowerCase();
615
+ eventName = lowerCase(eventName);
609
616
  _eventListeners[eventName] = _eventListeners[eventName] || /* @__PURE__ */ new Set();
610
617
  _eventListeners[eventName].add(callback);
611
618
  return () => _eventListeners && _eventListeners[eventName].delete(callback);
@@ -621,19 +628,36 @@
621
628
  */
622
629
  emit(eventName, arg1, arg2, arg3, arg4) {
623
630
  if (_initialized) {
624
- eventName = eventName.toLowerCase();
631
+ eventName = lowerCase(eventName);
625
632
  triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
626
633
  triggerEvent(eventName, arg1, arg2, arg3, arg4);
627
634
  triggerEvent("after:" + eventName, arg1, arg2, arg3, arg4);
628
635
  }
629
636
  },
630
637
  /**
631
- * Set or reset the color palette
638
+ * Set or reset the color palette.
632
639
  *
633
640
  * @param {string[]} [colors]
634
641
  */
635
642
  pal(colors = defaultPalette) {
636
643
  _colors = colors;
644
+ _currentPalette = [...colors];
645
+ },
646
+ /**
647
+ * Swap two colors of the current palette.
648
+ *
649
+ * If called without arguments, reset the current palette.
650
+ *
651
+ * @param {number?} a
652
+ * @param {number?} b
653
+ */
654
+ palc(a, b) {
655
+ if (a == null) {
656
+ _colors = [..._currentPalette];
657
+ } else {
658
+ ;
659
+ [_colors[a], _colors[b]] = [_colors[b], _colors[a]];
660
+ }
637
661
  },
638
662
  /**
639
663
  * Define or update a instance property.
@@ -668,11 +692,11 @@
668
692
  /**
669
693
  * Returns information about that engine instance.
670
694
  *
671
- * @param {number} n
695
+ * @param {number|string} index
672
696
  * @returns {any}
673
697
  */
674
- stat(n) {
675
- const list = [
698
+ stat(index) {
699
+ const internals = [
676
700
  // 0
677
701
  settings,
678
702
  // 1
@@ -698,7 +722,7 @@
698
722
  // 11
699
723
  _fontFamily
700
724
  ];
701
- const data = { index: n, value: list[n] };
725
+ const data = { index, value: internals[index] };
702
726
  instance.emit("stat", data);
703
727
  return data.value;
704
728
  },
@@ -924,12 +948,12 @@
924
948
  const _keysDown = /* @__PURE__ */ new Set();
925
949
  const _keysPress = /* @__PURE__ */ new Set();
926
950
  const keyCheck = (keySet, key = "") => {
927
- key = key.toLowerCase();
951
+ key = lowerCase(key);
928
952
  return !key ? keySet.size > 0 : keySet.has("space" === key ? " " : key);
929
953
  };
930
954
  let _lastKey = "";
931
955
  on(root, "keydown", (event) => {
932
- const key = event.key.toLowerCase();
956
+ const key = lowerCase(event.key);
933
957
  if (!_keysDown.has(key)) {
934
958
  _keysDown.add(key);
935
959
  _keysPress.add(key);
@@ -937,7 +961,7 @@
937
961
  }
938
962
  });
939
963
  on(root, "keyup", (event) => {
940
- _keysDown.delete(event.key.toLowerCase());
964
+ _keysDown.delete(lowerCase(event.key));
941
965
  });
942
966
  on(root, "blur", () => _keysDown.clear());
943
967
  instance.listen("after:update", () => _keysPress.clear());
@@ -974,9 +998,7 @@
974
998
  instance.resume();
975
999
  }
976
1000
  function drawFrame() {
977
- if (!settings.animate) {
978
- return instance.emit("draw", _ctx);
979
- }
1001
+ _rafid = raf(drawFrame);
980
1002
  let now = Date.now();
981
1003
  let updated = 0;
982
1004
  let frameTime = now - _lastFrameTime;
@@ -995,7 +1017,6 @@
995
1017
  _accumulated = 0;
996
1018
  }
997
1019
  }
998
- _rafid = raf(drawFrame);
999
1020
  }
1000
1021
  function setupCanvas() {
1001
1022
  if ("string" === typeof settings.canvas) {
@@ -1006,11 +1027,11 @@
1006
1027
  _canvas = _canvas || document.createElement("canvas");
1007
1028
  _ctx = _canvas.getContext("2d");
1008
1029
  on(_canvas, "click", () => focus());
1009
- _canvas.style = "";
1010
1030
  resizeCanvas();
1011
1031
  if (!_canvas.parentNode) {
1012
1032
  document.body.appendChild(_canvas);
1013
1033
  }
1034
+ _canvas.style.imageRendering = "pixelated";
1014
1035
  _canvas.oncontextmenu = () => false;
1015
1036
  }
1016
1037
  function resizeCanvas() {
@@ -1030,15 +1051,9 @@
1030
1051
  _canvas.style.width = width * _scale + "px";
1031
1052
  _canvas.style.height = height * _scale + "px";
1032
1053
  }
1033
- if (settings.pixelart) {
1034
- _ctx.imageSmoothingEnabled = false;
1035
- _canvas.style.imageRendering = "pixelated";
1036
- }
1054
+ _ctx.imageSmoothingEnabled = false;
1037
1055
  instance.textalign("start", "top");
1038
1056
  instance.emit("resized", _scale);
1039
- if (!settings.animate) {
1040
- raf(drawFrame);
1041
- }
1042
1057
  }
1043
1058
  function triggerEvent(eventName, arg1, arg2, arg3, arg4) {
1044
1059
  if (!_eventListeners[eventName]) return;
@@ -1060,6 +1075,7 @@
1060
1075
  root.ENGINE = instance;
1061
1076
  }
1062
1077
  setupCanvas();
1078
+ instance.pal();
1063
1079
  if ("loading" === document.readyState) {
1064
1080
  on(root, "DOMContentLoaded", () => raf(init));
1065
1081
  } else {
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.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}})();
1
+ (()=>{var e=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(t={}){let a=window,l=Math,n=2*l.PI,i=requestAnimationFrame,o=[],r=(e,t,a)=>{e.addEventListener(t,a,!1),o.push(()=>e.removeEventListener(t,a,!1))},s=e=>e.toLowerCase(),c=e=>e.preventDefault(),f=e=>e.beginPath(),d=(e=>{let t=new AudioContext;return e.zzfxV=1,(a=1,l=.05,n=220,i=0,o=0,r=.1,s=0,c=1,f=0,d=0,u=0,p=0,h=0,m=0,g=0,v=0,w=0,x=1,y=0,b=0,k=0)=>{let E=Math,z=2*E.PI,T=f*=500*z/44100/44100,I=n*=(1-l+2*l*E.random(l=[]))*z/44100,D=0,S=0,A=0,M=1,C=0,L=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(i=44100*i+9,y*=44100,o*=44100,r*=44100,w*=44100,d*=500*z/85766121e6,g*=z/44100,u*=z/44100,p*=44100,h=44100*h|0,a*=.3*e.zzfxV,P=i+y+o+r+w|0;A<P;l[A++]=N*a)++L%(100*v|0)||(N=s?1<s?2<s?3<s?B(D*D):E.max(E.min(E.tan(D),1),-1):1-(2*D/z%2+2)%2:1-4*E.abs(E.round(D/z)-D/z):B(D),N=(h?1-b+b*B(z*A/h):1)*(N<0?-1:1)*E.abs(N)**c*(A<i?A/i:A<i+y?1-(A-i)/y*(1-x):A<i+y+o?x:A<P-w?(P-A-w)/r*x:0),N=w?N/2+(w>A?0:(A<P-w?1:(P-A)/w)*l[A-w|0]/2/a):N,k&&(N=j=R*X+G*(X=Y)+R*(Y=N)-W*$-V*($=j))),D+=(F=(n+=f+=d)*E.cos(g*S++))+F*m*B(A**5),M&&++M>p&&(n+=u,I+=u,M=0),!h||++C%h||(n=I,f=T,M=M||1);(a=t.createBuffer(1,P,44100)).getChannelData(0).set(l),(n=t.createBufferSource()).buffer=a,n.connect(t.destination),n.start()}})(a);t=Object.assign({width:null,height:null,autoscale:!0,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0},t);let u=!1,p=[],h,m=1,g,v=.5,w=1,x,y=1e3/60,b,k,E="sans-serif",z=20,T=Date.now(),I,D,S=[.5,0,1750,,,.3,1,,,,600,.1],A={},M={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:n,HALF_PI:n/4,lerp:(e,t,a)=>a*(t-e)+e,deg2rad:e=>l.PI/180*e,rad2deg:e=>180/l.PI*e,round:(e,t=0)=>{if(!t)return l.round(e);let a=10**t;return l.round(e*a)/a},clamp:(e,t,a)=>e<t?t:e>a?a:e,wrap:(e,t,a)=>e-(a-t)*l.floor((e-t)/(a-t)),map(e,t,a,l,n,i){let o=(e-t)/(a-t)*(n-l)+l;return i?M.clamp(o,l,n):o},norm:(e,t,a)=>M.map(e,t,a,0,1),wave:(e,t,a,l=Math.sin)=>e+(l(a)+1)/2*(t-e),rand:(e=0,t=1)=>(T=(1664525*T+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>l.floor(M.rand(e,t+1)),rseed(e){T=~~e},cls(e){null==e?g.clearRect(0,0,g.canvas.width,g.canvas.height):M.rectfill(0,0,g.canvas.width,g.canvas.height,e)},rect(e,t,a,l,n,i){f(g),g[i?"roundRect":"rect"](~~e-v,~~t-v,~~a+2*v,~~l+2*v,i),M.stroke(n)},rectfill(e,t,a,l,n,i){f(g),g[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),M.fill(n)},circ(e,t,a,l){f(g),g.arc(~~e,~~t,~~a,0,n),M.stroke(l)},circfill(e,t,a,l){f(g),g.arc(~~e,~~t,~~a,0,n),M.fill(l)},oval(e,t,a,l,i){f(g),g.ellipse(~~e,~~t,~~a,~~l,0,0,n),M.stroke(i)},ovalfill(e,t,a,l,i){f(g),g.ellipse(~~e,~~t,~~a,~~l,0,0,n),M.fill(i)},line(e,t,a,l,n){f(g);let i=.5*(0!==v&&~~e==~~a),o=.5*(0!==v&&~~t==~~l);g.moveTo(~~e+i,~~t+o),g.lineTo(~~a+i,~~l+o),M.stroke(n)},linewidth(e){g.lineWidth=~~e,v=.5*(0!=~~e%2)},linedash(e,t=0){g.setLineDash(e),g.lineDashOffset=t},text(e,t,a,l=3,n="normal"){g.font=`${n} ${z}px ${E}`,g.fillStyle=D[~~l%D.length],g.fillText(a,~~e,~~t)},textfont(e){E=e},textsize(e){z=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,l,n){let i=n.replace(/\s/g,"");for(let n=0;n<a;n++)for(let a=0;a<l;a++){let o=i[l*a+n]||".";"."!==o&&M.rectfill(e+n,t+a,1,1,parseInt(o,16)||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(){g.save()},pop(){g.restore()},translate(e,t){g.translate(~~e,~~t)},scale(e,t){g.scale(e,t||e)},rotate(e){g.rotate(e)},alpha(e){g.globalAlpha=M.clamp(e,0,1)},fill(e){g.fillStyle=D[~~e%D.length],g.fill()},stroke(e){g.strokeStyle=D[~~e%D.length],g.stroke()},clip(e){f(g),e(g),g.clip()},sfx:(e,t=0,l=1)=>!!a.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||S,(0!==t||1!==l)&&((e=e.slice())[0]=l*(e[0]||1),e[10]=~~e[10]+t),d.apply(0,e),e),volume(e){a.zzfxV=e},canvas:()=>h,use(e,t={}){u?F(e,t):p.push([e,t])},listen:(e,t)=>(A[e=s(e)]=A[e]||new Set,A[e].add(t),()=>A&&A[e].delete(t)),emit(e,t,a,l,n){u&&(P("before:"+(e=s(e)),t,a,l,n),P(e,t,a,l,n),P("after:"+e,t,a,l,n))},pal(t=e){D=t,I=[...t]},palc(e,t){null==e?D=[...I]:[D[e],D[t]]=[D[t],D[e]]},def(e,l){M[e]=l,t.global&&(a[e]=l)},timescale(e){w=e},framerate(e){y=1e3/~~e},stat(e){let l={index:e,value:[t,u,y/1e3,m,A,D,S,w,a.zzfxV,T,z,E][e]};return M.emit("stat",l),l.value},quit(){for(let e of(M.pause(),M.emit("quit"),A={},o))e();if(t.global){for(let e in M)delete a[e];delete a.ENGINE}u=!1},pause(){cancelAnimationFrame(k),k=0},resume(){u&&!k&&(b=y,x=Date.now(),k=i(L))},paused:()=>!k};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))M[e]=l[e];function C(){let e=t.loop?t.loop:a;for(let t of"init,update,draw,tap,untap,tapping,tapped,resized".split(","))e[t]&&M.listen(t,e[t]);for(let[e,t]of p)F(e,t);if(t.autoscale&&r(a,"resize",N),t.tapEvents){let e=e=>[(e.pageX-h.offsetLeft)/m,(e.pageY-h.offsetTop)/m],t=new Map,l=(e,a,l)=>{let n={x:a,y:l,xi:a,yi:l,t:Date.now()};return t.set(e,n),n},n=(e,a,n)=>{let i=t.get(e)||l(e);i.x=a,i.y=n},i=e=>e&&Date.now()-e.t<=300,o=!1;r(h,"mousedown",t=>{if(0===t.button){c(t);let[a,n]=e(t);M.emit("tap",a,n,0),l(0,a,n),o=!0}}),r(h,"mouseup",a=>{if(0===a.button){c(a);let l=t.get(0),[n,r]=e(a);i(l)&&M.emit("tapped",l.xi,l.yi,0),M.emit("untap",n,r,0),t.delete(0),o=!1}}),r(a,"mousemove",t=>{c(t);let[a,l]=e(t);M.def("MX",a),M.def("MY",l),o&&(M.emit("tapping",a,l,0),n(0,a,l))}),r(h,"touchstart",t=>{for(let a of(c(t),t.changedTouches)){let[t,n]=e(a);M.emit("tap",t,n,a.identifier+1),l(a.identifier+1,t,n)}}),r(h,"touchmove",t=>{for(let a of(c(t),t.changedTouches)){let[t,l]=e(a);M.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let s=e=>{c(e);let a=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,l]of t)a.includes(e)||(i(l)&&M.emit("tapped",l.xi,l.yi,e),M.emit("untap",l.x,l.y,e),t.delete(e))};r(h,"touchend",s),r(h,"touchcancel",s),r(a,"blur",()=>{for(let[e,a]of(o=!1,t))M.emit("untap",a.x,a.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,l=(e,t="")=>(t=s(t))?e.has("space"===t?" ":t):e.size>0,n="";r(a,"keydown",a=>{let l=s(a.key);e.has(l)||(e.add(l),t.add(l),n=" "===l?"space":l)}),r(a,"keyup",t=>{e.delete(s(t.key))}),r(a,"blur",()=>e.clear()),M.listen("after:update",()=>t.clear()),M.def("iskeydown",t=>l(e,t)),M.def("iskeypressed",e=>l(t,e)),M.def("lastkey",()=>n)}u=!0,M.emit("init",M),M.resume()}function L(){k=i(L);let e=Date.now(),t=0,a=e-x;for(x=e,b+=a<100?a:y;b>=y;){t++,b-=y;let e=y/1e3*w;M.emit("update",e,t),M.def("T",M.T+e)}t&&(M.emit("draw",g),t>1&&(b=0))}function N(){let e=t.width>0?t.width:innerWidth,a=t.width>0?t.height||t.width:innerHeight;if(M.def("W",e),M.def("H",a),h.width=e,h.height=a,t.autoscale){let n=+t.autoscale;h.style.display||(h.style.display="block",h.style.margin="auto"),m=l.min(innerWidth/e,innerHeight/a),m=n>1&&m>n?n:m,h.style.width=e*m+"px",h.style.height=a*m+"px"}g.imageSmoothingEnabled=!1,M.textalign("start","top"),M.emit("resized",m)}function P(e,t,a,l,n){if(A[e])for(let i of A[e])i(t,a,l,n)}function F(e,t){let a=e(M,t);for(let e in a)M.def(e,a[e])}if(t.global){if(a.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(a,M),a.ENGINE=M}return g=(h=(h="string"==typeof t.canvas?document.querySelector(t.canvas):t.canvas)||document.createElement("canvas")).getContext("2d"),r(h,"click",()=>focus()),N(),h.parentNode||document.body.appendChild(h),h.style.imageRendering="pixelated",h.oncontextmenu=()=>!1,M.pal(),"loading"===document.readyState?r(a,"DOMContentLoaded",()=>i(C)):i(C),M}})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.95.1",
3
+ "version": "0.97.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.2",
36
+ "@swc/core": "^1.13.3",
37
37
  "@types/jsdom": "^21.1.7",
38
38
  "ava": "^6.4.1",
39
39
  "esbuild": "^0.25.8",
@@ -55,8 +55,8 @@
55
55
  "test:watch": "ava --watch",
56
56
  "dev": "esbuild src/web.js --bundle --watch --outfile=samples/dist.js --servedir=samples",
57
57
  "build": "npm run genversion && node script/build.js && size-limit",
58
- "format": "prettier -w src/* samples/* types/* script/* types/*",
59
- "check-types": "npx ts types/*",
58
+ "format": "prettier -w src/* samples/* types/* script/* tests/*",
59
+ "check-types": "npx tsc ./types/*",
60
60
  "genversion": "genversion --es6 src/version.js"
61
61
  },
62
62
  "files": [