UNPKG

litecanvas

Version:

Lightweight HTML5 canvas 2D game engine suitable for small projects and creative coding. Inspired by PICO-8 and P5/Processing.

1 lines 7.88 kB
(()=>{var e=new AudioContext,t=(t=1,a=.05,n=220,i=0,l=0,r=.1,o=0,s=1,c=0,f=0,d=0,p=0,u=0,g=0,h=0,m=0,v=0,E=1,b=0,w=0,x=0)=>{let y=Math,T=2*y.PI,I=c*=500*T/44100/44100,S=n*=(1-a+2*a*y.random(a=[]))*T/44100,k=0,A=0,H=0,D=1,P=0,C=0,X=0,N=x<0?-1:1,L=T*N*x*2/44100,O=y.cos(L),Y=y.sin,z=Y(L)/4,F=1+z,G=-2*O/F,M=(1-z)/F,R=(1+N*O)/2/F,W=-(N+O)/F,B=0,U=0,q=0,V=0;for(i=44100*i+9,b*=44100,l*=44100,r*=44100,v*=44100,f*=500*T/85766121e6,h*=T/44100,d*=T/44100,p*=44100,u=44100*u|0,t*=.3*(globalThis.zzfxV||1),N=i+b+l+r+v|0;H<N;a[H++]=X*t)++C%(100*m|0)||(X=o?1<o?2<o?3<o?Y(k*k):y.max(y.min(y.tan(k),1),-1):1-(2*k/T%2+2)%2:1-4*y.abs(y.round(k/T)-k/T):Y(k),X=(u?1-w+w*Y(T*H/u):1)*(X<0?-1:1)*y.abs(X)**s*(H<i?H/i:H<i+b?1-(H-i)/b*(1-E):H<i+b+l?E:H<N-v?(N-H-v)/r*E:0),X=v?X/2+(v>H?0:(H<N-v?1:(N-H)/v)*a[H-v|0]/2/t):X,x&&(X=V=R*B+W*(B=U)+R*(U=X)-M*q-G*(q=V))),k+=(L=(n+=c+=f)*y.cos(h*A++))+L*g*Y(H**5),D&&++D>p&&(n+=d,S+=d,D=0),!u||++P%u||(n=S,c=I,D=D||1);(t=e.createBuffer(1,N,44100)).getChannelData(0).set(a),(n=e.createBufferSource()).buffer=t,n.connect(e.destination),n.start()},a=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(e={}){let n=globalThis,i=Math,l=2*i.PI,r=requestAnimationFrame,o=[],s=(e,t,a)=>{e.addEventListener(t,a,!1),o.push(()=>e.removeEventListener(t,a,!1))};e=Object.assign({width:null,height:null,autoscale:!0,pixelart:!1,antialias:!1,canvas:null,global:!0,loop:null,pauseOnBlur:!0,tapEvents:!0,keyboardEvents:!0,animate:!0},e);let c=!1,f=[],d,p=1,u,g=.5,h=1,m,v=1/60,E=0,b,w="sans-serif",x=20,y=Date.now(),T={init:!1,update:!1,draw:!1,resized:!1,tap:!1,untap:!1,tapping:!1,tapped:!1},I={settings:Object.assign({},e),colors:a},S={WIDTH:0,HEIGHT:0,CANVAS:!1,ELAPSED:0,CENTERX:0,CENTERY:0,MOUSEX:-1,MOUSEY:-1,DEFAULT_SFX:[.5,0,1750,,,.3,1,,,,600,.1],TWO_PI:l,HALF_PI:i.PI/2,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,n,i,l){let r=(e-t)/(a-t)*(i-n)+n;return l?S.clamp(r,n,i):r},norm:(e,t,a)=>S.map(e,t,a,0,1),rand:(e=0,t=1)=>(y=(1664525*y+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>i.floor(S.rand(e,t+1)),seed:e=>null==e?y:y=~~e,cls(e){null==e?u.clearRect(0,0,u.canvas.width,u.canvas.height):S.rectfill(0,0,u.canvas.width,u.canvas.height,e)},rect(e,t,a,n,i,l){u.beginPath(),u[l?"roundRect":"rect"](~~e-g,~~t-g,~~a+2*g,~~n+2*g,l),S.stroke(i)},rectfill(e,t,a,n,i,l){u.beginPath(),u[l?"roundRect":"rect"](~~e,~~t,~~a,~~n,l),S.fill(i)},circ(e,t,a,n){u.beginPath(),u.arc(~~e,~~t,~~a,0,l),S.stroke(n)},circfill(e,t,a,n){u.beginPath(),u.arc(~~e,~~t,~~a,0,l),S.fill(n)},line(e,t,a,n,i){u.beginPath();let l=.5*(0!==g&&~~e==~~a),r=.5*(0!==g&&~~t==~~n);u.moveTo(~~e+l,~~t+r),u.lineTo(~~a+l,~~n+r),S.stroke(i)},linewidth(e){u.lineWidth=~~e,g=.5*(0!=~~e%2)},linedash(e,t=0){u.setLineDash(e),u.lineDashOffset=t},text(e,t,a,n=3,i="normal"){u.font=`${i} ${x}px ${w}`,u.fillStyle=S.getcolor(n),u.fillText(a,~~e,~~t)},textfont(e){w=e},textsize(e){x=e},textalign(e,t){e&&(u.textAlign=e),t&&(u.textBaseline=t)},image(e,t,a){u.drawImage(a,~~e,~~t)},paint(e,t,a,n={}){let i=n.canvas||new OffscreenCanvas(1,1),l=n.scale||1,r=u;if(i.width=e*l,i.height=t*l,(u=i.getContext("2d")).scale(l,l),a.push){let e=0,t=0;for(let n of(u.imageSmoothingEnabled=!1,a)){for(let a of n)" "!==a&&"."!==a&&S.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(u);return u=r,i.transferToImageBitmap()},ctx:e=>(e&&(u=e),u),push:()=>u.save(),pop:()=>u.restore(),translate:(e,t)=>u.translate(~~e,~~t),scale:(e,t)=>u.scale(e,t||e),rotate:e=>u.rotate(e),alpha(e){u.globalAlpha=S.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){u.fillStyle=S.getcolor(e),t?u.fill(t):u.fill()},stroke(e,t){u.strokeStyle=S.getcolor(e),t?u.stroke(t):u.stroke()},clip(e){u.clip(e)},sfx:(e,a=0,i=1)=>!(n.zzfxV<=0)&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||S.DEFAULT_SFX,(0!==a||1!==i)&&((e=e.slice())[0]=i*(e[0]||1),e[10]=~~e[10]+a),t.apply(0,e),e),volume(e){n.zzfxV=e},use(e,t={}){c?P(e,t):f.push([e,t])},listen:(e,t)=>(T[e]=T[e]||new Set,T[e].add(t),()=>T[e].delete(t)),emit(e,t,a,n,i){c&&(D("before:"+e,t,a,n,i),D(e,t,a,n,i),D("after:"+e,t,a,n,i))},getcolor:e=>a[~~e%a.length],setvar(t,a){S[t]=a,e.global&&(n[t]=a)},timescale(e){h=e},setfps(e){v=1/~~e},quit(){for(let e of(cancelAnimationFrame(b),S.emit("quit"),T=[],o))e();if(e.global){for(let e in S)delete n[e];delete n.ENGINE}}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))S[e]=i[e];function k(){c=!0;let t=e.loop?e.loop:n;for(let e in T)t[e]&&S.listen(e,t[e]);for(let[e,t]of f)P(e,t);if(e.autoscale&&s(n,"resize",H),e.tapEvents){let e=(e,t)=>[(e-d.offsetLeft)/p,(t-d.offsetTop)/p],t=new Map,a=(e,a,n)=>{let i={x:a,y:n,startX:a,startY:n,ts:performance.now()};return t.set(e,i),i},i=(e,n,i)=>{let l=t.get(e)||a(e);l.x=n,l.y=i},l=e=>e&&performance.now()-e.ts<=300,r=e=>e.preventDefault(),o=!1;s(d,"mousedown",t=>{if(0===t.button){r(t);let[n,i]=e(t.pageX,t.pageY);S.emit("tap",n,i,0),a(0,n,i),o=!0}}),s(d,"mouseup",a=>{if(0===a.button){r(a);let n=t.get(0),[i,s]=e(a.pageX,a.pageY);l(n)&&S.emit("tapped",n.startX,n.startY,0),S.emit("untap",i,s,0),t.delete(0),o=!1}}),s(d,"mousemove",t=>{r(t);let[a,n]=e(t.pageX,t.pageY);S.setvar("MOUSEX",a),S.setvar("MOUSEY",n),o&&(S.emit("tapping",a,n,0),i(0,a,n))}),s(d,"touchstart",t=>{for(let n of(r(t),t.changedTouches)){let[t,i]=e(n.pageX,n.pageY);S.emit("tap",t,i,n.identifier+1),a(n.identifier+1,t,i)}}),s(d,"touchmove",t=>{for(let a of(r(t),t.changedTouches)){let[t,n]=e(a.pageX,a.pageY);S.emit("tapping",t,n,a.identifier+1),i(a.identifier+1,t,n)}});let c=e=>{r(e);let a=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,n]of t)a.includes(e)||(l(n)&&S.emit("tapped",n.startX,n.startY,e),S.emit("untap",n.x,n.y,e),t.delete(e))};s(d,"touchend",c),s(d,"touchcancel",c),s(n,"blur",()=>{for(let[e,a]of(o=!1,t))S.emit("untap",a.x,a.y,e),t.delete(e)})}if(e.keyboardEvents){let e=e=>e.toLowerCase(),t=new Set,a=new Set,i=(t,a)=>a?t.has("space"===e(a)?" ":e(a)):t.size>0;s(n,"keydown",n=>{t.has(e(n.key))||(t.add(e(n.key)),a.add(e(n.key)))}),s(n,"keyup",a=>{t.delete(e(a.key))}),s(n,"blur",()=>t.clear()),S.listen("after:draw",()=>a.clear()),S.setvar("iskeydown",e=>i(t,e)),S.setvar("iskeypressed",e=>i(a,e))}e.pauseOnBlur&&(s(n,"blur",()=>{b=cancelAnimationFrame(b)}),s(n,"focus",()=>{b||(b=r(A))})),S.emit("init",S),m=performance.now(),b=r(A)}function A(t){let a=0,n=(t-m)/1e3;if(m=t,e.animate){if(b=r(A),n>.3)return;for(E+=n;E>=v;)S.emit("update",v*h),S.setvar("ELAPSED",S.ELAPSED+v*h),a++,E-=v}else a=1;a&&(S.textalign("start","top"),S.emit("draw"))}function H(){let t=e.width||n.innerWidth,a=e.height||e.width||n.innerHeight;S.setvar("WIDTH",d.width=t),S.setvar("HEIGHT",d.height=a),S.setvar("CENTERX",S.WIDTH/2),S.setvar("CENTERY",S.HEIGHT/2),e.autoscale&&(d.style.display||(d.style.display="block",d.style.margin="auto"),p=i.min(n.innerWidth/S.WIDTH,n.innerHeight/S.HEIGHT),p=(e.pixelart?~~p:p)||1,d.style.width=S.WIDTH*p+"px",d.style.height=S.HEIGHT*p+"px"),(!e.antialias||e.pixelart)&&(u.imageSmoothingEnabled=!1,d.style.imageRendering="pixelated"),S.emit("resized",p),e.animate||r(A)}function D(e,t,a,n,i){if(T[e])for(let l of T[e])l(t,a,n,i)}function P(e,t){let a=e(S,I,t);for(let e in a)S.setvar(e,a[e])}if(e.global){if(n.ENGINE)throw Error("two global litecanvas detected");Object.assign(n,S),n.ENGINE=S}return d="string"==typeof(d=e.canvas||document.createElement("canvas"))?document.querySelector(d):d,S.setvar("CANVAS",d),u=d.getContext("2d"),s(d,"click",()=>n.focus()),d.style="",H(),d.parentNode||document.body.appendChild(d),"loading"===document.readyState?s(n,"DOMContentLoaded",()=>r(k)):r(k),S}})();