litecanvas 0.98.0 → 0.98.1

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 CHANGED
@@ -32,7 +32,7 @@
32
32
  };
33
33
 
34
34
  // src/version.js
35
- var version = "0.98.0";
35
+ var version = "0.98.1";
36
36
 
37
37
  // src/index.js
38
38
  function litecanvas(settings = {}) {
@@ -50,7 +50,7 @@
50
50
  keyboardEvents: true
51
51
  };
52
52
  settings = Object.assign(defaults, settings);
53
- let _initialized = false, _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 = {};
53
+ let _initialized = false, _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _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 = {};
54
54
  const instance = {
55
55
  /** @type {number} */
56
56
  W: 0,
@@ -565,7 +565,7 @@
565
565
  "[litecanvas] text() 5th param must be a string"
566
566
  );
567
567
  _ctx.font = `${fontStyle} ${_fontSize}px ${_fontFamily}`;
568
- _ctx.fillStyle = _colors[~~color % _colors.length];
568
+ _ctx.fillStyle = getColor(color);
569
569
  _ctx.fillText(message, ~~x, ~~y);
570
570
  },
571
571
  /**
@@ -772,7 +772,7 @@
772
772
  null == color || isNumber(color) && color >= 0,
773
773
  "[litecanvas] fill() 1st param must be a positive number or zero"
774
774
  );
775
- _ctx.fillStyle = _colors[~~color % _colors.length];
775
+ _ctx.fillStyle = getColor(color);
776
776
  _ctx.fill();
777
777
  },
778
778
  /**
@@ -785,7 +785,7 @@
785
785
  null == color || isNumber(color) && color >= 0,
786
786
  "[litecanvas] stroke() 1st param must be a positive number or zero"
787
787
  );
788
- _ctx.strokeStyle = _colors[~~color % _colors.length];
788
+ _ctx.strokeStyle = getColor(color);
789
789
  _ctx.stroke();
790
790
  },
791
791
  /**
@@ -913,7 +913,7 @@
913
913
  }
914
914
  },
915
915
  /**
916
- * Set or reset the color palette.
916
+ * Set new palette colors or restore the default palette.
917
917
  *
918
918
  * @param {string[]} [colors]
919
919
  */
@@ -922,14 +922,16 @@
922
922
  Array.isArray(colors) && colors.length > 0,
923
923
  "[litecanvas] pal() 1st param must be a array of strings"
924
924
  );
925
- _colors = colors;
926
- _currentPalette = [...colors];
925
+ _colorPalette = colors;
926
+ _colorPaletteState = [];
927
927
  },
928
928
  /**
929
- * Swap two colors of the current palette.
929
+ * Replace the color "a" with color "b".
930
930
  *
931
931
  * If called without arguments, reset the current palette.
932
932
  *
933
+ * Note: `palc()` don't affect drawings made with `image()`.
934
+ *
933
935
  * @param {number?} a
934
936
  * @param {number?} b
935
937
  */
@@ -943,10 +945,9 @@
943
945
  "[litecanvas] palc() 2nd param must be a positive number"
944
946
  );
945
947
  if (a == null) {
946
- _colors = [..._currentPalette];
948
+ _colorPaletteState = [];
947
949
  } else {
948
- ;
949
- [_colors[a], _colors[b]] = [_colors[b], _colors[a]];
950
+ _colorPaletteState[a] = b;
950
951
  }
951
952
  },
952
953
  /**
@@ -1016,7 +1017,7 @@
1016
1017
  // 4
1017
1018
  _eventListeners,
1018
1019
  // 5
1019
- _colors,
1020
+ _colorPalette,
1020
1021
  // 6
1021
1022
  _defaultSound,
1022
1023
  // 7
@@ -1410,6 +1411,10 @@
1410
1411
  instance.def(key, pluginData[key]);
1411
1412
  }
1412
1413
  }
1414
+ function getColor(index) {
1415
+ const i = _colorPaletteState[index] ?? index;
1416
+ return _colorPalette[~~i % _colorPalette.length];
1417
+ }
1413
1418
  if (settings.global) {
1414
1419
  if (root.ENGINE) {
1415
1420
  throw new Error("only one global litecanvas is allowed");
@@ -1420,7 +1425,6 @@
1420
1425
  DEV: console.info(`[litecanvas] version ${version} started`);
1421
1426
  DEV: console.debug(`[litecanvas] litecanvas() options =`, settings);
1422
1427
  setupCanvas();
1423
- instance.pal();
1424
1428
  if ("loading" === document.readyState) {
1425
1429
  on(root, "DOMContentLoaded", () => raf(init));
1426
1430
  } else {
package/dist/dist.js CHANGED
@@ -42,7 +42,7 @@
42
42
  keyboardEvents: true
43
43
  };
44
44
  settings = Object.assign(defaults, settings);
45
- let _initialized = false, _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 = {};
45
+ let _initialized = false, _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _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 = {};
46
46
  const instance = {
47
47
  /** @type {number} */
48
48
  W: 0,
@@ -373,7 +373,7 @@
373
373
  */
374
374
  text(x, y, message, color = 3, fontStyle = "normal") {
375
375
  _ctx.font = `${fontStyle} ${_fontSize}px ${_fontFamily}`;
376
- _ctx.fillStyle = _colors[~~color % _colors.length];
376
+ _ctx.fillStyle = getColor(color);
377
377
  _ctx.fillText(message, ~~x, ~~y);
378
378
  },
379
379
  /**
@@ -528,7 +528,7 @@
528
528
  * @param {number} [color=0]
529
529
  */
530
530
  fill(color) {
531
- _ctx.fillStyle = _colors[~~color % _colors.length];
531
+ _ctx.fillStyle = getColor(color);
532
532
  _ctx.fill();
533
533
  },
534
534
  /**
@@ -537,7 +537,7 @@
537
537
  * @param {number} [color=0]
538
538
  */
539
539
  stroke(color) {
540
- _ctx.strokeStyle = _colors[~~color % _colors.length];
540
+ _ctx.strokeStyle = getColor(color);
541
541
  _ctx.stroke();
542
542
  },
543
543
  /**
@@ -631,28 +631,29 @@
631
631
  }
632
632
  },
633
633
  /**
634
- * Set or reset the color palette.
634
+ * Set new palette colors or restore the default palette.
635
635
  *
636
636
  * @param {string[]} [colors]
637
637
  */
638
638
  pal(colors = defaultPalette) {
639
- _colors = colors;
640
- _currentPalette = [...colors];
639
+ _colorPalette = colors;
640
+ _colorPaletteState = [];
641
641
  },
642
642
  /**
643
- * Swap two colors of the current palette.
643
+ * Replace the color "a" with color "b".
644
644
  *
645
645
  * If called without arguments, reset the current palette.
646
646
  *
647
+ * Note: `palc()` don't affect drawings made with `image()`.
648
+ *
647
649
  * @param {number?} a
648
650
  * @param {number?} b
649
651
  */
650
652
  palc(a, b) {
651
653
  if (a == null) {
652
- _colors = [..._currentPalette];
654
+ _colorPaletteState = [];
653
655
  } else {
654
- ;
655
- [_colors[a], _colors[b]] = [_colors[b], _colors[a]];
656
+ _colorPaletteState[a] = b;
656
657
  }
657
658
  },
658
659
  /**
@@ -704,7 +705,7 @@
704
705
  // 4
705
706
  _eventListeners,
706
707
  // 5
707
- _colors,
708
+ _colorPalette,
708
709
  // 6
709
710
  _defaultSound,
710
711
  // 7
@@ -1060,6 +1061,10 @@
1060
1061
  instance.def(key, pluginData[key]);
1061
1062
  }
1062
1063
  }
1064
+ function getColor(index) {
1065
+ const i = _colorPaletteState[index] ?? index;
1066
+ return _colorPalette[~~i % _colorPalette.length];
1067
+ }
1063
1068
  if (settings.global) {
1064
1069
  if (root.ENGINE) {
1065
1070
  throw new Error("only one global litecanvas is allowed");
@@ -1068,7 +1073,6 @@
1068
1073
  root.ENGINE = instance;
1069
1074
  }
1070
1075
  setupCanvas();
1071
- instance.pal();
1072
1076
  if ("loading" === document.readyState) {
1073
1077
  on(root, "DOMContentLoaded", () => raf(init));
1074
1078
  } 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,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=1,m,g=.5,v=1,w,x=1e3/60,y,b,k="sans-serif",E=20,z=Date.now(),T,I,D=[.5,0,1750,,,.3,1,,,,600,.1],S={},A={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?A.clamp(o,l,n):o},norm:(e,t,a)=>A.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)=>(z=(1664525*z+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>l.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,l,n,i){f(m),m[i?"roundRect":"rect"](~~e-g,~~t-g,~~a+2*g,~~l+2*g,i),A.stroke(n)},rectfill(e,t,a,l,n,i){f(m),m[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),A.fill(n)},circ(e,t,a,l){f(m),m.arc(~~e,~~t,~~a,0,n),A.stroke(l)},circfill(e,t,a,l){f(m),m.arc(~~e,~~t,~~a,0,n),A.fill(l)},oval(e,t,a,l,i){f(m),m.ellipse(~~e,~~t,~~a,~~l,0,0,n),A.stroke(i)},ovalfill(e,t,a,l,i){f(m),m.ellipse(~~e,~~t,~~a,~~l,0,0,n),A.fill(i)},line(e,t,a,l,n){f(m);let i=.5*(0!==g&&~~e==~~a),o=.5*(0!==g&&~~t==~~l);m.moveTo(~~e+i,~~t+o),m.lineTo(~~a+i,~~l+o),A.stroke(n)},linewidth(e){m.lineWidth=~~e,g=.5*(0!=~~e%2)},linedash(e,t=0){m.setLineDash(e),m.lineDashOffset=t},text(e,t,a,l=3,n="normal"){m.font=`${n} ${E}px ${k}`,m.fillStyle=I[~~l%I.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)},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&&A.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=m;return n.width=e*i,n.height=t*i,(m=n.getContext("2d")).scale(i,i),a(m),m=o,n.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=I[~~e%I.length],m.fill()},stroke(e){m.strokeStyle=I[~~e%I.length],m.stroke()},clip(e){f(m),e(m),m.clip()},sfx:(e,t=0,l=1)=>!!a.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||D,(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:()=>p,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=s(e)]=S[e]||new Set,S[e].add(t),()=>S&&S[e].delete(t)),emit(e,t,a,l,n){u&&(N("before:"+(e=s(e)),t,a,l,n),N(e,t,a,l,n),N("after:"+e,t,a,l,n))},pal(t=e){I=t,T=[...t]},palc(e,t){null==e?I=[...T]:[I[e],I[t]]=[I[t],I[e]]},def(e,l){A[e]=l,t.global&&(a[e]=l)},timescale(e){v=e},framerate(e){x=1e3/~~e},stat(e){let l={index:e,value:[t,u,x/1e3,h,S,I,D,v,a.zzfxV,z,E,k][e]};return A.emit("stat",l),l.value},quit(){for(let e of(A.pause(),A.emit("quit"),S={},o))e();if(t.global){for(let e in A)delete a[e];delete a.ENGINE}u=!1},pause(){cancelAnimationFrame(b),b=0},resume(){u&&!b&&(y=x,w=Date.now(),b=i(C))},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]=l[e];function M(){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]);if(t.autoscale&&r(a,"resize",L),t.tapEvents){let e=e=>[(e.pageX-p.offsetLeft)/h,(e.pageY-p.offsetTop)/h],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(p,"mousedown",t=>{if(0===t.button){c(t);let[a,n]=e(t);A.emit("tap",a,n,0),l(0,a,n),o=!0}}),r(p,"mouseup",a=>{if(0===a.button){c(a);let l=t.get(0),[n,r]=e(a);i(l)&&A.emit("tapped",l.xi,l.yi,0),A.emit("untap",n,r,0),t.delete(0),o=!1}}),r(a,"mousemove",t=>{c(t);let[a,l]=e(t);A.def("MX",a),A.def("MY",l),o&&(A.emit("tapping",a,l,0),n(0,a,l))}),r(p,"touchstart",t=>{for(let a of(c(t),t.changedTouches)){let[t,n]=e(a);A.emit("tap",t,n,a.identifier+1),l(a.identifier+1,t,n)}}),r(p,"touchmove",t=>{for(let a of(c(t),t.changedTouches)){let[t,l]=e(a);A.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)&&A.emit("tapped",l.xi,l.yi,e),A.emit("untap",l.x,l.y,e),t.delete(e))};r(p,"touchend",s),r(p,"touchcancel",s),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,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()),A.listen("after:update",()=>t.clear()),A.def("iskeydown",t=>l(e,t)),A.def("iskeypressed",e=>l(t,e)),A.def("lastkey",()=>n)}u=!0,A.emit("init",A),A.resume()}function C(){b=i(C);let e=Date.now(),t=0,a=e-w;for(w=e,y+=a<100?a:x;y>=x;){t++,y-=x;let e=x/1e3*v;A.emit("update",e,t),A.def("T",A.T+e)}t&&(A.emit("draw",m),t>1&&(y=0))}function L(){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 n=+t.autoscale;p.style.display||(p.style.display="block",p.style.margin="auto"),h=l.min(innerWidth/e,innerHeight/a),h=n>1&&h>n?n:h,p.style.width=e*h+"px",p.style.height=a*h+"px"}m.imageSmoothingEnabled=!1,A.textalign("start","top"),A.emit("resized",h)}function N(e,t,a,l,n){if(S[e])for(let i of S[e])i(t,a,l,n)}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()),L(),p.parentNode||document.body.appendChild(p),p.style.imageRendering="pixelated",p.oncontextmenu=()=>!1,A.pal(),"loading"===document.readyState?r(a,"DOMContentLoaded",()=>i(M)):i(M),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=1,m,g=.5,v=1,w,x=1e3/60,y,b,k="sans-serif",E=20,z=Date.now(),T=e,I=[],D=[.5,0,1750,,,.3,1,,,,600,.1],S={},A={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?A.clamp(o,l,n):o},norm:(e,t,a)=>A.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)=>(z=(1664525*z+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>l.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,l,n,i){f(m),m[i?"roundRect":"rect"](~~e-g,~~t-g,~~a+2*g,~~l+2*g,i),A.stroke(n)},rectfill(e,t,a,l,n,i){f(m),m[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),A.fill(n)},circ(e,t,a,l){f(m),m.arc(~~e,~~t,~~a,0,n),A.stroke(l)},circfill(e,t,a,l){f(m),m.arc(~~e,~~t,~~a,0,n),A.fill(l)},oval(e,t,a,l,i){f(m),m.ellipse(~~e,~~t,~~a,~~l,0,0,n),A.stroke(i)},ovalfill(e,t,a,l,i){f(m),m.ellipse(~~e,~~t,~~a,~~l,0,0,n),A.fill(i)},line(e,t,a,l,n){f(m);let i=.5*(0!==g&&~~e==~~a),o=.5*(0!==g&&~~t==~~l);m.moveTo(~~e+i,~~t+o),m.lineTo(~~a+i,~~l+o),A.stroke(n)},linewidth(e){m.lineWidth=~~e,g=.5*(0!=~~e%2)},linedash(e,t=0){m.setLineDash(e),m.lineDashOffset=t},text(e,t,a,l=3,n="normal"){m.font=`${n} ${E}px ${k}`,m.fillStyle=P(l),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)},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&&A.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=m;return n.width=e*i,n.height=t*i,(m=n.getContext("2d")).scale(i,i),a(m),m=o,n.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=P(e),m.fill()},stroke(e){m.strokeStyle=P(e),m.stroke()},clip(e){f(m),e(m),m.clip()},sfx:(e,t=0,l=1)=>!!a.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||D,(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:()=>p,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=s(e)]=S[e]||new Set,S[e].add(t),()=>S&&S[e].delete(t)),emit(e,t,a,l,n){u&&(N("before:"+(e=s(e)),t,a,l,n),N(e,t,a,l,n),N("after:"+e,t,a,l,n))},pal(t=e){T=t,I=[]},palc(e,t){null==e?I=[]:I[e]=t},def(e,l){A[e]=l,t.global&&(a[e]=l)},timescale(e){v=e},framerate(e){x=1e3/~~e},stat(e){let l={index:e,value:[t,u,x/1e3,h,S,T,D,v,a.zzfxV,z,E,k][e]};return A.emit("stat",l),l.value},quit(){for(let e of(A.pause(),A.emit("quit"),S={},o))e();if(t.global){for(let e in A)delete a[e];delete a.ENGINE}u=!1},pause(){cancelAnimationFrame(b),b=0},resume(){u&&!b&&(y=x,w=Date.now(),b=i(C))},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]=l[e];function M(){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]);if(t.autoscale&&r(a,"resize",L),t.tapEvents){let e=e=>[(e.pageX-p.offsetLeft)/h,(e.pageY-p.offsetTop)/h],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(p,"mousedown",t=>{if(0===t.button){c(t);let[a,n]=e(t);A.emit("tap",a,n,0),l(0,a,n),o=!0}}),r(p,"mouseup",a=>{if(0===a.button){c(a);let l=t.get(0),[n,r]=e(a);i(l)&&A.emit("tapped",l.xi,l.yi,0),A.emit("untap",n,r,0),t.delete(0),o=!1}}),r(a,"mousemove",t=>{c(t);let[a,l]=e(t);A.def("MX",a),A.def("MY",l),o&&(A.emit("tapping",a,l,0),n(0,a,l))}),r(p,"touchstart",t=>{for(let a of(c(t),t.changedTouches)){let[t,n]=e(a);A.emit("tap",t,n,a.identifier+1),l(a.identifier+1,t,n)}}),r(p,"touchmove",t=>{for(let a of(c(t),t.changedTouches)){let[t,l]=e(a);A.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)&&A.emit("tapped",l.xi,l.yi,e),A.emit("untap",l.x,l.y,e),t.delete(e))};r(p,"touchend",s),r(p,"touchcancel",s),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,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()),A.listen("after:update",()=>t.clear()),A.def("iskeydown",t=>l(e,t)),A.def("iskeypressed",e=>l(t,e)),A.def("lastkey",()=>n)}u=!0,A.emit("init",A),A.resume()}function C(){b=i(C);let e=Date.now(),t=0,a=e-w;for(w=e,y+=a<100?a:x;y>=x;){t++,y-=x;let e=x/1e3*v;A.emit("update",e,t),A.def("T",A.T+e)}t&&(A.emit("draw",m),t>1&&(y=0))}function L(){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 n=+t.autoscale;p.style.display||(p.style.display="block",p.style.margin="auto"),h=l.min(innerWidth/e,innerHeight/a),h=n>1&&h>n?n:h,p.style.width=e*h+"px",p.style.height=a*h+"px"}m.imageSmoothingEnabled=!1,A.textalign("start","top"),A.emit("resized",h)}function N(e,t,a,l,n){if(S[e])for(let i of S[e])i(t,a,l,n)}function P(e){return T[~~(I[e]??e)%T.length]}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()),L(),p.parentNode||document.body.appendChild(p),p.style.imageRendering="pixelated",p.oncontextmenu=()=>!1,"loading"===document.readyState?r(a,"DOMContentLoaded",()=>i(M)):i(M),A}})();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.98.0",
4
- "description": "Lightweight HTML5 canvas 2D game engine suitable for small projects and creative coding. Inspired by PICO-8 and P5/Processing.",
3
+ "version": "0.98.1",
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>",
7
7
  "contributors": [],
package/src/index.js CHANGED
@@ -73,9 +73,9 @@ export default function litecanvas(settings = {}) {
73
73
  /** @type {number} */
74
74
  _rngSeed = Date.now(),
75
75
  /** @type {string[]} */
76
- _currentPalette,
77
- /** @type {string[]} */
78
- _colors,
76
+ _colorPalette = defaultPalette,
77
+ /** @type {number[]} */
78
+ _colorPaletteState = [],
79
79
  /** @type {number[]} */
80
80
  _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1],
81
81
  /** @type {string} */
@@ -659,7 +659,7 @@ export default function litecanvas(settings = {}) {
659
659
  )
660
660
 
661
661
  _ctx.font = `${fontStyle} ${_fontSize}px ${_fontFamily}`
662
- _ctx.fillStyle = _colors[~~color % _colors.length]
662
+ _ctx.fillStyle = getColor(color)
663
663
  _ctx.fillText(message, ~~x, ~~y)
664
664
  },
665
665
 
@@ -899,7 +899,7 @@ export default function litecanvas(settings = {}) {
899
899
  '[litecanvas] fill() 1st param must be a positive number or zero'
900
900
  )
901
901
 
902
- _ctx.fillStyle = _colors[~~color % _colors.length]
902
+ _ctx.fillStyle = getColor(color)
903
903
  _ctx.fill()
904
904
  },
905
905
 
@@ -914,7 +914,7 @@ export default function litecanvas(settings = {}) {
914
914
  '[litecanvas] stroke() 1st param must be a positive number or zero'
915
915
  )
916
916
 
917
- _ctx.strokeStyle = _colors[~~color % _colors.length]
917
+ _ctx.strokeStyle = getColor(color)
918
918
  _ctx.stroke()
919
919
  },
920
920
 
@@ -1067,7 +1067,7 @@ export default function litecanvas(settings = {}) {
1067
1067
  },
1068
1068
 
1069
1069
  /**
1070
- * Set or reset the color palette.
1070
+ * Set new palette colors or restore the default palette.
1071
1071
  *
1072
1072
  * @param {string[]} [colors]
1073
1073
  */
@@ -1076,15 +1076,17 @@ export default function litecanvas(settings = {}) {
1076
1076
  Array.isArray(colors) && colors.length > 0,
1077
1077
  '[litecanvas] pal() 1st param must be a array of strings'
1078
1078
  )
1079
- _colors = colors
1080
- _currentPalette = [...colors]
1079
+ _colorPalette = colors
1080
+ _colorPaletteState = []
1081
1081
  },
1082
1082
 
1083
1083
  /**
1084
- * Swap two colors of the current palette.
1084
+ * Replace the color "a" with color "b".
1085
1085
  *
1086
1086
  * If called without arguments, reset the current palette.
1087
1087
  *
1088
+ * Note: `palc()` don't affect drawings made with `image()`.
1089
+ *
1088
1090
  * @param {number?} a
1089
1091
  * @param {number?} b
1090
1092
  */
@@ -1098,9 +1100,9 @@ export default function litecanvas(settings = {}) {
1098
1100
  '[litecanvas] palc() 2nd param must be a positive number'
1099
1101
  )
1100
1102
  if (a == null) {
1101
- _colors = [..._currentPalette]
1103
+ _colorPaletteState = []
1102
1104
  } else {
1103
- ;[_colors[a], _colors[b]] = [_colors[b], _colors[a]]
1105
+ _colorPaletteState[a] = b
1104
1106
  }
1105
1107
  },
1106
1108
 
@@ -1178,7 +1180,7 @@ export default function litecanvas(settings = {}) {
1178
1180
  // 4
1179
1181
  _eventListeners,
1180
1182
  // 5
1181
- _colors,
1183
+ _colorPalette,
1182
1184
  // 6
1183
1185
  _defaultSound,
1184
1186
  // 7
@@ -1687,6 +1689,15 @@ export default function litecanvas(settings = {}) {
1687
1689
  }
1688
1690
  }
1689
1691
 
1692
+ /**
1693
+ * @param {number} index
1694
+ * @returns {string}
1695
+ */
1696
+ function getColor(index) {
1697
+ const i = _colorPaletteState[index] ?? index
1698
+ return _colorPalette[~~i % _colorPalette.length]
1699
+ }
1700
+
1690
1701
  if (settings.global) {
1691
1702
  if (root.ENGINE) {
1692
1703
  throw new Error('only one global litecanvas is allowed')
@@ -1700,9 +1711,6 @@ export default function litecanvas(settings = {}) {
1700
1711
 
1701
1712
  setupCanvas()
1702
1713
 
1703
- // init the color palette
1704
- instance.pal()
1705
-
1706
1714
  if ('loading' === document.readyState) {
1707
1715
  on(root, 'DOMContentLoaded', () => raf(init))
1708
1716
  } else {
package/src/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '0.98.0'
2
+ export const version = '0.98.1'
package/types/global.d.ts CHANGED
@@ -545,13 +545,13 @@ declare global {
545
545
  */
546
546
  function emit(event: string, arg1?: any, arg2?: any, arg3?: any, arg4?: any): void
547
547
  /**
548
- * Set or reset the color palette.
548
+ * Set new palette colors or restore the default palette.
549
549
  *
550
550
  * @param [colors]
551
551
  */
552
552
  function pal(colors?: string[]): void
553
553
  /**
554
- * Swap two colors of the current palette.
554
+ * Replace the color "a" with color "b".
555
555
  *
556
556
  * If called without arguments, reset the current palette.
557
557
  *
package/types/types.d.ts CHANGED
@@ -542,13 +542,13 @@ type LitecanvasInstance = {
542
542
  */
543
543
  def(key: string, value: any): void
544
544
  /**
545
- * Set or reset the color palette.
545
+ * Set new palette colors or restore the default palette.
546
546
  *
547
547
  * @param [colors]
548
548
  */
549
549
  pal(colors?: string[]): void
550
550
  /**
551
- * Swap two colors of the current palette.
551
+ * Replace the color "a" with color "b".
552
552
  *
553
553
  * If called without arguments, reset the current palette.
554
554
  *