From 07b35b96679ffc7a79cca2902406de9b8d848368 Mon Sep 17 00:00:00 2001 From: versustunez Date: Fri, 7 Aug 2020 19:31:30 +0200 Subject: [PATCH] WIP --- build/task/js.js | 1 + build/task/spriteBuilder.js | 1 + index.html | 5 ++ out/gui/wave.json | 2 +- out/icon-sprite.svg | 2 +- out/js/scripts.js | 158 ++++++++++++++++++++++++++++----- out/js/scripts.min.js | 2 +- out/theme/style.css | 2 +- out/tpl/help.tpl | 69 ++++++++++++++ out/tpl/image.tpl | 3 +- raw/gui/wave.json | 30 +++++++ raw/javascript/app.js | 5 +- raw/javascript/eventHandler.js | 58 ++++++++---- raw/javascript/gui.js | 18 +++- raw/javascript/keys.js | 59 ++++++++++++ raw/javascript/notification.js | 2 +- raw/javascript/player.js | 2 +- raw/javascript/utils.js | 4 + raw/javascript/visuals/wave.js | 10 ++- raw/scss/_gui.scss | 30 +++++++ raw/scss/_playlist.scss | 6 ++ shaders/sphere.frag | 2 - shaders/water.frag | 2 - shaders/wave.frag | 11 +-- shaders/wave.vert | 6 -- shaders/wave2d.frag | 11 ++- shaders/wave2d.vert | 7 -- 27 files changed, 429 insertions(+), 79 deletions(-) create mode 100644 out/tpl/help.tpl create mode 100644 raw/javascript/keys.js diff --git a/build/task/js.js b/build/task/js.js index a295e68..ec727ac 100644 --- a/build/task/js.js +++ b/build/task/js.js @@ -30,6 +30,7 @@ const config = { ...visuals, basePath + 'eventHandler.js', basePath + 'select.js', + basePath + 'keys.js', basePath + 'startup.js', basePath + 'app.js' ], diff --git a/build/task/spriteBuilder.js b/build/task/spriteBuilder.js index edd45f9..5da45df 100644 --- a/build/task/spriteBuilder.js +++ b/build/task/spriteBuilder.js @@ -43,6 +43,7 @@ function buildIconSprites() { fal.faFolderUpload, fal.faListMusic, fal.faFileImage, + fal.faQuestionCircle, ], vt: [] }; diff --git a/index.html b/index.html index 3e9cf34..62a7feb 100644 --- a/index.html +++ b/index.html @@ -36,6 +36,11 @@ +
`}}class Modal{constructor(){this.currentModal="",this.modal=$("#modal"),this.parent=this.modal.parentNode,this.modal.addDelegatedEventListener("click","header .close",this.closeModal.bind(this))}resetModal(){this.renderModal("","","")}renderModal(t,e,a){$("#modal").removeClass("lightMode"),this.currentModal=t,this.renderHeader(t),this.renderContent(e),this.renderFooter(a)}renderHeader(t){$("header .headline",this.modal).innerHTML=t}renderContent(t){$("modal-content",this.modal).innerHTML=t}renderFooter(t){$("modal-footer .inner",this.modal).innerHTML=t||"by VersusTuneZ"}closeModal(){this.parent.addClass("hide")}isCurrent(t){return t===this.currentModal}showModal(){this.parent.removeClass("hide")}}class Visual{constructor(){this.data=[],this.dataArray=[],this.name="Default"}updateData(){}updateFFT(t){}draw(){}setup(){}}class VisualDrawer{constructor(){this.visuals={wave:new Wave,wave2d:new Wave2D},this.lastMainColor={base:"#-1",color:[0,0,0]},this.lastSecondColor={base:"#-1",color:[0,0,0]}}init(){this.switch(pConf.get("visual","wave2d")),this.updateLoop()}switch(t){null!=this.visuals[t]&&(this.c=t,vConf.loadConfigByName(this.c),this.visuals[this.c].setup(),pConf.set("visual",this.c),pConf.save())}updateLoop(){let t=this.visuals[this.c],e=shaderHandler.use(this.c);this.updateSeekbar(),this.prepare(e),t.updateData(),t.draw(e),requestAnimationFrame(this.updateLoop.bind(this))}updateSeekbar(){cInfo.width=window.innerWidth,cInfo.height=window.innerHeight;let t=audioHandler.audioFile;if(ctx.clearRect(0,0,cInfo.width,cInfo.height),!t.paused&&pConf.get("showSeekbar",!0)){let e=t.duration,a=t.currentTime/e*cInfo.width;ctx.fillStyle=pConf.get("seekColor","#fff"),ctx.fillRect(0,c.height-10,a,c.height)}}prepare(t){c.width=window.innerWidth,c.height=window.innerHeight,gl.viewport(0,0,gl.canvas.width,gl.canvas.height),gl.clearColor(0,0,0,parseFloat(pConf.get("alphaValue",0))),gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT),gl.enable(gl.DEPTH_TEST),gl.depthFunc(gl.LEQUAL),gl.enable(gl.CULL_FACE),this.setColor(t)}setColor(t){let e=gl.getUniformLocation(t,"u_baseColor"),a=gl.getUniformLocation(t,"u_maxColor"),i=this.lastMainColor,s=this.lastSecondColor;this.updateColor("lastMainColor","baseColor"),this.updateColor("lastSecondColor","gradientToColor"),gl.uniform3fv(e,i.color),gl.uniform3fv(a,s.color)}updateColor(t,e){let a=this[t],i=vConf.get(e,"#ffffff");i!==a.base&&(a.color=hexToRgb(i),a.base=i)}}class ImageUploader{async init(){this.image=pConf.get("bgURL",""),this.color=pConf.get("bgColour","#000000"),this.alpha=pConf.get("alphaValue",.5),this.getRealImage(),this.applyValues(),$("#modal").addDelegatedEventListener("change",'#image-upload input:not([type="color"])',this.changeHandler.bind(this)),$("#modal").addDelegatedEventListener("input","#image-upload input#color",this.changeHandler.bind(this))}async renderModal(){await template.loadTemplate("image"),gui.modal.resetModal(),gui.modal.renderModal("Background-Image",template.parseTemplate("image",{value:this.image,bgValue:this.color,alphaValue:this.alpha}),""),gui.modal.showModal()}changeHandler(t,e){"color"===e.id?this.color=e.value:"alphaValue"===e.id?this.alpha=e.value:(pConf.set("bgMode",e.id),"image"===e.id?(e.files[0].toBase64((t,e)=>{e?alert("Error converting image!"):(pConf.set("bgURL",t.currentTarget.result),pConf.save())}),this.image=URL.createObjectURL(e.files[0])):(this.image=e.value,pConf.set("bgURL",this.image))),pConf.set("bgColour",this.color),pConf.set("alphaValue",this.alpha),this.applyValues(),pConf.save()}applyValues(){let t=$("body");t.style.backgroundImage="url("+this.image+")",t.style.backgroundColor=this.color}getRealImage(){let t=pConf.get("bgMode"),e=pConf.get("bgURL","");if("image"===t){if(""!==e&&e.startsWith("data:image")){let t=e.split(";"),a=t.shift(),i=t.join(";").replace("base64,","");this.image=URL.createObjectURL(b64toBlob(i,a))}}else this.image=e}}const imageUploader=new ImageUploader;class NotificationHandler{static instance=new NotificationHandler;constructor(){this.outer=$(".notification"),this.notifications=[]}async init(){await template.loadTemplate("notification")}static createNotification(t,e,a){a=parseInt(a||"3000");let i=NotificationHandler.instance,s=new Notification(t,e,a);return i.notifications.push(s),s.show(),s}}class Notification{constructor(t,e,a){this.outer=NotificationHandler.instance.outer,this.message=t,this.type=e,this.time=a,this.isRemoved=!1}async show(){let t=this,e=-1===t.time;t.item=create("div"),t.item.addClass("notification-item, "+t.type),e&&(t.type+=" endless"),t.updateContent(t.message),this.outer.appendChild(t.item),e||setTimeout(this.remove.bind(this),t.time)}async remove(){if(this.isRemoved)return;this.isRemoved=!0,this.outer.removeChild(this.item);let t=NotificationHandler.instance.notifications,e=t.indexOf(this);t.splice(e,1)}updateContent(t){let e={message:t,time:-1===this.time?1e3:this.time+1,type:this.type};this.item.innerHTML=template.parseTemplate("notification",e)}updateMessageOnly(t){let e=$(".message",this.item);e&&(e.innerHTML=t)}}class Config{static allConfigs={};constructor(t){this.config={},this.name="",this.type=t,Config.allConfigs[t]=this}loadConfigByName(t){this.save(),this.name="config-"+t;let e=localStorage.getItem(this.name);e&&(this.config=JSON.parse(e))}save(){""!==this.name&&localStorage.setItem(this.name,JSON.stringify(this.config))}set(t,e){this.config[t]=e}remove(t){delete this.config[t]}get(t,e){let a=this.config[t];return null==a&&(this.config[t]=e,a=e),a}reset(){NotificationHandler.createNotification("CONFIG REQUEST SUCCESS FOR "+this.type,"success",2e3),this.config={},this.save()}}class Sphere extends Visual{constructor(){super(),this.name="Sphere"}draw(){}setup(){}}class Wave extends Visual{constructor(){super(),this.name="3D Wave"}updateData(){let t=audioHandler.getFloatArray(),e=2/t.length,a=-1,i=0;for(let s=0;s{player.playlist.renderPagination(player.playlist.page),gui.modal.showModal()}),t.addDelegatedEventListener("click",".playlist-item",(t,e)=>{let a=e.dataset.index;player.playByID(parseInt(a)),togglePlayButton("pause")}),t.addDelegatedEventListener("click",".controls button",(t,e)=>{switch(e.id){case"previous":player.prevSong();break;case"next":player.nextSong();break;case"play":player.playStop();break;case"shuffle":player.playlist.isShuffle=!player.playlist.isShuffle,toggleShuffle()}togglePlayButton(audioHandler.audioFile.paused?"play":"pause")}),window.addEventListener("playSong",setActiveOnPlaylist),$(".upload-image").addEventListener("click",imageUploader.renderModal.bind(imageUploader)),t.addDelegatedEventListener("click",".readAll",t=>{let e=player.playlist.list;for(let t=0;t{$(".current",e.parentNode).innerText=e.value}),t.addDelegatedEventListener("input",'input[type="color"]',(t,e)=>{$(".colorBlob",e.parentNode).style.backgroundColor=e.value}),t.addDelegatedEventListener("click",".visual-item",(t,e)=>{visual.switch(e.dataset.id||"wave"),$("modal-content .visuals .active").removeClass("active"),e.addClass("active")}),t.addDelegatedEventListener("input","section.base input",(t,e)=>{"checkbox"===e.type?pConf.set(e.name,e.checked):setValue(e.name,e.value,pConf,e.dataset.type),pConf.save()}),t.addDelegatedEventListener("input","section.visual input",(t,e)=>{"checkbox"===e.type?vConf.set(e.name,e.checked):setValue(e.name,e.value,vConf,e.dataset.type),vConf.save()}),t.addDelegatedEventListener("click",".button[data-action]",(t,e)=>{switch(e.dataset.action){case"resetVConf":vConf.reset(),setTimeout(t=>{playerConf.handleById()},30);break;case"makeModalTransparent":$("#modal").toggleClass("lightMode")}})}function setValue(t,e,a,i){switch(i){case"float":e=parseFloat(e);break;case"int":e=parseInt(e)}a.set(t,e)}function setActiveOnPlaylist(t){let e=$('.playlist-item[data-index="'+player.playlist.index+'"]'),a=$(".playlist-item.active");a&&a.removeClass("active"),e&&e.addClass("active")}function toggleShuffle(){let t=player.playlist.isShuffle;$("#shuffle").toggleCheck("active",t);let e=t?"enabled":"disabled";NotificationHandler.createNotification("Shuffle: "+e,"info",500)}function togglePlayButton(t){$$("#play .icon").forEach(e=>{e.dataset.name===t?e.removeClass("hide"):e.addClass("hide")})}!function(){const t=$("body");t.addDelegatedEventListener("click","custom-select .label",(t,e)=>{let a=e.parentNode,i=$$("custom-option",a),s=$("custom-options",a);if(a.hasClass("open"))s.style.maxHeight="",a.removeClass("open");else{let t=0;i.forEach((function(e){t+=e.offsetHeight})),s.style.maxHeight=t+"px",a.addClass("open")}}),t.addDelegatedEventListener("click","custom-select custom-option",(t,e)=>{let a=e.closest("custom-select"),i=$("input",a);$$("custom-option.active").forEach(t=>{t.removeClass("active")}),e.addClass("active"),i&&(i.value=e.dataset.value||e.innerText,$(".label",a).innerText=e.innerText,a.removeClass("open"),e.parentNode.style.maxHeight="",window.dispatchEvent(new CustomEvent("selectChanged",{detail:{select:a,event:a.dataset.event,value:i.value,name:i.name}})))}),window.addEventListener("selectChanged",t=>{"visualConf"===t.detail.event&&(t.preventDefault(),t.stopPropagation(),function(t){try{let e=t.value,a=Config.allConfigs[t.select.dataset.conf];"fftSize"===t.name&&(e=parseInt(t.value),visual.visuals[visual.c].updateFFT(e)),a.set(t.name,e),a.save()}catch(t){console.error(t)}}(t.detail))})}();class Startup{constructor(){this.modules={startup:!1,"id3-ready":!1}}moduleLoaded(t){this.modules[t]=!0,this.allModulesLoaded()}allModulesLoaded(){for(let t in this.modules)if(!this.modules[t])return!1;return window.dispatchEvent(new CustomEvent("startupFin")),!0}}const shaderHandler=new ShaderHandler(null),audioHandler=new AudioHandler,gui=new GUI,visual=new VisualDrawer,template=new Template,player=new Player,vConf=new Config("visual"),pConf=new Config("player"),worker=new Worker("/out/js/worker.min.js"),startup=new Startup,eventHandler=new EventHandler,playerConf=new PlayerConfigHandler;let c,gl,cInfo,ctx;async function startUP(){if(pConf.loadConfigByName("default"),c=$("#c"),gl=c.getContext("webgl2"),cInfo=$("#cInfo"),ctx=cInfo.getContext("2d"),!gl)return alert("SORRY THE BROWSER DOESN'T SUPPORT WEBGL2"),!1;shaderHandler.setGL(gl),await shaderHandler.loadArray(["wave","sphere","water","wave2d"],"shaders/"),await NotificationHandler.instance.init(),await audioHandler.init(),await player.init(),await visual.init(),await gui.init(),await imageUploader.init(),await playerConf.init(),await initHandler()}worker.addEventListener("message",t=>{"startup"!==t.data.status?eventHandler.handleEvent(t):startup.moduleLoaded(t.data.cmd)}),window.addEventListener("startupFin",t=>{setTimeout(t=>{$(".loading-screen").remove()},100)}),startUP().then(t=>{startup.moduleLoaded("startup")}); \ No newline at end of file +class VTUtils{static random(e,t){let a=Math.random();if(void 0===e)return a;if(void 0===t)return e instanceof Array?e[Math.floor(a*e.length)]:a*e;if(e>t){let a=e;e=t,t=a}return a*(t-e)+e}static randomInt(e,t){return Math.floor(VTUtils.random(e,t))}static normalize(e,t,a){return(e-a)/(t-a)}static distance(e,t,a,i){let s=e-a,n=t-i;return Math.sqrt(s*s+n*n)}static map(e,t,a,i,s,n){let l=(e-t)/(a-t)*(s-i)+i;return n?i>16&255)/255,(t>>8&255)/255,(255&t)/255]}Node.prototype.addDelegatedEventListener=function(e,t,a){this.addEventListener(e,e=>{let i=e.target;if(i.matches(t))a(e,i);else{let s=i.closest(t);if(s)try{a(e,s)}catch(e){NotificationHandler.createNotification("FATAL ERROR WITHIN HANDLER!","error",1e3)}}})},Node.prototype.hasClass=function(e){let t=e.split(","),a=null;for(let e of t){if(!1===a)break;a=this.classList.contains(e.trim())}return!0===a},Node.prototype.addClass=function(e){let t=e.split(",");for(let e of t)this.classList.add(e.trim());return this},Node.prototype.removeClass=function(e){let t=e.split(",");for(let e of t)this.classList.remove(e.trim());return this},Node.prototype.toggleClass=function(e,t){let a=e.split(",");for(let e of a)this.classList.toggle(e.trim(),t)},Node.prototype.switchClass=function(e,t,a){let i=this.classList;a?(i.remove(e),i.add(t)):(i.remove(t),i.add(e))},Node.prototype.toggleCheck=function(e,t){let a=this.classList,i=e.split(",");for(let e of i){let i=e.trim();t?a.add(i):a.remove(i)}},String.prototype.firstUpper=function(){return this.charAt(0).toUpperCase()+this.slice(1)},File.prototype.toBase64=function(e){const t=new FileReader;t.onloadend=e,t.readAsDataURL(this)};class TDUtils{static lastMatrix={m:null};static multiply(e,t){let a=t[0],i=t[1],s=t[2],n=t[3],l=t[4],r=t[5],o=t[6],d=t[7],c=t[8],h=t[9],u=t[10],p=t[11],g=t[12],f=t[13],m=t[14],y=t[15],v=e[0],C=e[1],w=e[2],T=e[3],S=e[4],b=e[5],H=e[6],x=e[7],U=e[8],D=e[9],A=e[10],E=e[11],L=e[12],R=e[13],F=e[14],M=e[15];return[a*v+i*S+s*U+n*L,a*C+i*b+s*D+n*R,a*w+i*H+s*A+n*F,a*T+i*x+s*E+n*M,l*v+r*S+o*U+d*L,l*C+r*b+o*D+d*R,l*w+r*H+o*A+d*F,l*T+r*x+o*E+d*M,c*v+h*S+u*U+p*L,c*C+h*b+u*D+p*R,c*w+h*H+u*A+p*F,c*T+h*x+u*E+p*M,g*v+f*S+m*U+y*L,g*C+f*b+m*D+y*R,g*w+f*H+m*A+y*F,g*T+f*x+m*E+y*M]}static translate(e,t,a,i,s){s=s||new Float32Array(16);let n=e[0],l=e[1],r=e[2],o=e[3],d=e[4],c=e[5],h=e[6],u=e[7],p=e[8],g=e[9],f=e[10],m=e[11],y=e[12],v=e[13],C=e[14],w=e[15];return s[0]=n,s[1]=l,s[2]=r,s[3]=o,s[4]=d,s[5]=c,s[6]=h,s[7]=u,s[8]=p,s[9]=g,s[10]=f,s[11]=m,s[12]=n*t+d*a+p*i+y,s[13]=l*t+c*a+g*i+v,s[14]=r*t+h*a+f*i+C,s[15]=o*t+u*a+m*i+w,s}static xRotation(e){e=TDUtils.degToRad(e);let t=Math.cos(e),a=Math.sin(e);return[1,0,0,0,0,t,a,0,0,-a,t,0,0,0,0,1]}static yRotation(e){e=TDUtils.degToRad(e);let t=Math.cos(e),a=Math.sin(e);return[t,0,-a,0,0,1,0,0,a,0,t,0,0,0,0,1]}static zRotation(e){e=TDUtils.degToRad(e);let t=Math.cos(e),a=Math.sin(e);return[t,a,0,0,-a,t,0,0,0,0,1,0,0,0,0,1]}static degToRad(e){return e*Math.PI/180}static scale(e,t,a,i){return(i=i||new Float32Array(16))[0]=e,i[5]=t,i[10]=a,i}static lookAt(e,t,a,i){i=i||new Float32Array(16);let s=TDUtils.normalize(TDUtils.subtractVectors(e,t)),n=TDUtils.normalize(TDUtils.cross(a,s)),l=TDUtils.normalize(TDUtils.cross(s,n));return i[0]=n[0],i[1]=n[1],i[2]=n[2],i[4]=l[0],i[5]=l[1],i[6]=l[2],i[8]=s[0],i[9]=s[1],i[10]=s[2],i[12]=e[0],i[13]=e[1],i[14]=e[2],i[15]=1,i}static cross(e,t,a){return(a=a||new Float32Array(3))[0]=e[1]*t[2]-e[2]*t[1],a[1]=e[2]*t[0]-e[0]*t[2],a[2]=e[0]*t[1]-e[1]*t[0],a}static normalize(e,t){t=t||new Float32Array(3);let a=Math.sqrt(e[0]*e[0]+e[1]*e[1]+e[2]*e[2]);return a>1e-5&&(t[0]=e[0]/a,t[1]=e[1]/a,t[2]=e[2]/a),t}static subtractVectors(e,t,a){return(a=a||new Float32Array(3))[0]=e[0]-t[0],a[1]=e[1]-t[1],a[2]=e[2]-t[2],a}static perspective(e,t,a,i,s){s=s||new Float32Array(16);let n=Math.tan(.5*Math.PI-.5*e),l=1/(a-i);return s[0]=n/t,s[5]=n,s[10]=(a+i)*l,s[11]=-1,s[14]=a*i*l*2,s}static inverse(e,t){t=t||new Float32Array(16);let a=e[0],i=e[1],s=e[2],n=e[3],l=e[4],r=e[5],o=e[6],d=e[7],c=e[8],h=e[9],u=e[10],p=e[11],g=e[12],f=e[13],m=e[14],y=e[15],v=u*y,C=m*p,w=o*y,T=m*d,S=o*p,b=u*d,H=s*y,x=m*n,U=s*p,D=u*n,A=s*d,E=o*n,L=c*f,R=g*h,F=l*f,M=g*r,k=l*h,I=c*r,N=a*f,P=g*i,V=a*h,$=c*i,B=a*r,O=l*i,z=v*r+T*h+S*f-(C*r+w*h+b*f),_=C*i+H*h+D*f-(v*i+x*h+U*f),G=w*i+x*r+A*f-(T*i+H*r+E*f),j=b*i+U*r+E*h-(S*i+D*r+A*h),K=1/(a*z+l*_+c*G+g*j);return t[0]=K*z,t[1]=K*_,t[2]=K*G,t[3]=K*j,t[4]=K*(C*l+w*c+b*g-(v*l+T*c+S*g)),t[5]=K*(v*a+x*c+U*g-(C*a+H*c+D*g)),t[6]=K*(T*a+H*l+E*g-(w*a+x*l+A*g)),t[7]=K*(S*a+D*l+A*c-(b*a+U*l+E*c)),t[8]=K*(L*d+M*p+k*y-(R*d+F*p+I*y)),t[9]=K*(R*n+N*p+$*y-(L*n+P*p+V*y)),t[10]=K*(F*n+P*d+B*y-(M*n+N*d+O*y)),t[11]=K*(I*n+V*d+O*p-(k*n+$*d+B*p)),t[12]=K*(F*u+I*m+R*o-(k*m+L*o+M*u)),t[13]=K*(V*m+L*s+P*u-(N*u+$*m+R*s)),t[14]=K*(N*o+O*m+M*s-(B*m+F*s+P*o)),t[15]=K*(B*u+k*s+$*o-(V*o+O*u+I*s)),t}static aspectView(e){return[1*e,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]}static getMatrix(e,t,a,i,s,n){let l=this.lastMatrix,r=TDUtils;if(!(r.isSame("fov",e)&&r.isSame("aspect",t)&&r.isSame("near",a)&&r.isSame("far",i)&&r.isSame("cam",s)&&r.isSame("radius",n))){let r=TDUtils.perspective(TDUtils.degToRad(e),t,a,i),o=TDUtils.yRotation(TDUtils.degToRad(s));o=TDUtils.translate(o,0,0,1.5*n);let d=TDUtils.inverse(o);r=TDUtils.multiply(r,d),l.m=r}return l.m}static isSame(e,t){let a=this.lastMatrix;return a[e]===t||(a[e]=t,!1)}static updateRotate(e,t){let a=vConf.get(e,t)+vConf.get(e+"-inc",0);a>360?a-=360:a<-360&&(a+=360),vConf.set(e,a)}}class Template{constructor(){this.tpl={}}async loadTemplate(e){let t=this;this.tpl[e]||await fetch(templateDir+e+".tpl").then(e=>e.text()).then(a=>{t.tpl[e]=a})}async loadArray(e){for(let t of e)await this.loadTemplate(t)}parseTemplate(e,t){if(!this.tpl[e])return"";let a,i=this.tpl[e];for(;null!==(a=templateEx.exec(i));){a.index===templateEx.lastIndex&&templateEx.lastIndex++;let e=a[0],s=t[a[1]];null==s&&(s=""),i=i.replace(e,s)}return i}parseFromAPI(e,t,a){fetch(e).then(e=>e.json()).then(e=>{a(this.parseTemplate(t,e))}).catch(console.error)}}const templateEx=/\$(.*?)\$/gm,templateDir="out/tpl/";class ShaderHandler{constructor(e){this.gl=e,this.shaderNames=[],this.shaders={},this.programs={}}setGL(e){this.gl=e}async loadShader(e,t){this.shaderNames.push(e),await this.load(e,t+e+".vert",this.gl.VERTEX_SHADER),await this.load(e,t+e+".frag",this.gl.FRAGMENT_SHADER)}async load(e,t,a){let i=e+"_"+a;if(!this.shaders[i]){let e=await fetch(t),s=this.createShader(await e.text(),a);s&&(this.shaders[i]=s)}return!!this.shaders[i]}getShader(e,t){let a=e+"_"+t;return this.shaders[a]}getAllShaders(){return this.shaderNames}async createProgramForEach(e){e=e||this.shaderNames;for(let t=0;t Currently no Song is uploaded!","error",2e3),!1;let t=this,a=e.file;t.lastSong&&URL.revokeObjectURL(t.lastSong),t.lastSong=this.audioFile.src=URL.createObjectURL(a),this.isStarted||this.start().catch(alert),this.audioFile.play().then(t=>{pConf.get("showPlaying","true")&&NotificationHandler.createNotification("Now Playing:"+e.getAudioName(),"info",pConf.get("showPlayingTime",1e3)),window.dispatchEvent(new CustomEvent("playSong"))}).catch(e=>{NotificationHandler.createNotification(e.message,"error",1e3),player.nextSong()})}getIntArray(e){let t=new Uint8Array(e);return this.analyser.getByteFrequencyData(t),t}getFloatArray(){let e=new Float32Array(this.analyser.fftSize);return this.analyser.getFloatTimeDomainData(e),e}}class AudioPlayerFile{constructor(e,t){this.file=e,this.name=this.getName(),this.id3=null,this.index=t}getName(){let e=this.file.name.split(".");return e.pop(),e=e.join("."),e}getID3Tag(e){return e||null===this.id3?(eventHandler.sendData("getData",{file:this.file,name:this.name,index:this.index,force:!0===e}),{title:this.name,artist:"VA"}):this.id3}getAudioName(){let e=this.getID3Tag();return template.parseTemplate("audio-information",e)}}class PlayerConfigHandler{async init(){await template.loadArray(["config/nav","config/content","config/visualitem"]),this.last="base",$(".settings-icon").addEventListener("click",this.open.bind(this)),$("modal-content").addDelegatedEventListener("click",".config-nav .item",this.navHandler.bind(this))}open(){if(void 0===this.content){let e=template.parseTemplate("config/nav",{});e+=template.parseTemplate("config/content",{content:""}),this.content=e}gui.modal.renderModal("Settings",this.content,"by VersusTuneZ"),this.handleById(),gui.modal.showModal()}navHandler(e,t){this.last=t.dataset.id,this.handleById()}handleById(){let e=this.last;new VisualConfig("visual"===e,"base"===e);let t=$(".config-nav .item.active"),a=$('.config-nav .item[data-id="'+e+'"]');t&&t.removeClass("active"),a&&a.addClass("active")}}class VisualConfig{static visualTemplates={};constructor(e,t){this.content=$("modal-content .config-content"),e?this.renderVisualConfig(visual.c):t?this.renderBase():this.renderVisuals()}renderVisuals(){let e=Object.keys(visual.visuals),t='
';for(let a=0;a",this.content.innerHTML=t}async renderBase(){let e=await this.loadVisualConfig("base"),t=create("section");t.addClass("base"),t.innerHTML=GUIHelper.fromJSON(e,pConf),this.content.innerHTML=t.outerHTML}async renderVisualConfig(e){let t=await this.loadVisualConfig(e,vConf),a=create("section");a.addClass("visual"),a.innerHTML=GUIHelper.fromJSON(t,vConf),a.innerHTML+=GUIHelper.createButton({action:"resetVConf",name:"Reset Visual Config"}),a.innerHTML+=GUIHelper.createButton({action:"makeModalTransparent",name:"toggle Modal Opacity"}),this.content.innerHTML=a.outerHTML}async loadVisualConfig(e){let t=VisualConfig.visualTemplates;return t[e]||(t[e]=await fetch("/out/gui/"+e+".json").then(e=>e.json())),t[e]}}class Player{async init(){this.playlist=new Playlist}nextSong(){let e=this.playlist.getNext();audioHandler.loadSong(e)}prevSong(){let e=this.playlist.getPrevious();audioHandler.loadSong(e)}playStop(){if(!audioHandler.lastSong){let e=this.playlist.getCurrent();return void audioHandler.loadSong(e)}let e=audioHandler.audioFile;e.paused?e.play():e.pause(),window.dispatchEvent(new CustomEvent("playSong"))}playByID(e){this.playlist.index=e;let t=this.playlist.getCurrent();audioHandler.loadSong(t)}}const PAGINATIONLIMIT=50;class Playlist{constructor(){this.list=[],this.shuffled=[],this.index=0,this.page=0,this.isShuffle=pConf.get("shuffle",!1),$("body").addDelegatedEventListener("change",'input[type="file"]',this.changeFiles.bind(this)),$("body").addDelegatedEventListener("click",".pagination .item",this.handlePagination.bind(this)),eventHandler.addEvent("id3-request",this.handle.bind(this)),eventHandler.addEvent("id3-request-force",this.forceID3.bind(this))}shuffle(){let e=this.list.length;if(e<3)this.shuffled=[0,1,2];else for(let t=0;tt&&(a=0),this.index=a,e[this.getRealIndex()]}getPrevious(){let e=this.list,t=e.length-1,a=this.index-1;return a<0&&(a=t),this.index=a,e[this.getRealIndex()]}getCurrent(){return this.list[this.getRealIndex()]}setPlaylist(e){this.index=0,this.forceData=void 0,this.list=e,this.shuffle()}handlePagination(e,t){t.hasClass("inactive")||(t.hasClass("next-site")?this.renderPagination(this.page+1):this.renderPagination(this.page-1))}renderPagination(e){void 0===e&&(e=this.page);let t=this.list.length,a=Math.ceil(t/50)-1;e<0&&(e=0),e>a&&(e=a);let i=50*e,s=i+50,n="";if(this.page=e,s>=t&&(s=t),t>0){let e=this.list;for(let t=i;t1&&e0?"active":"inactive",nextActive:l?"active":"inactive",page:e+1+" / "+parseInt(a+1)}))}changeFiles(e,t){if("upload-dir"!==t.id)return;let a=[],i=0;for(let e of t.files)if(e&&-1!==e.type.indexOf("audio")&&null===e.name.match(".m3u")){let t=new AudioPlayerFile(e,i++);a.push(t)}this.setPlaylist(a),a.length>0?(NotificationHandler.createNotification("Songs added successfully!
Songs: "+a.length,"success",3e3),this.renderPagination(0)):NotificationHandler.createNotification("File Upload failed!","error",3e3)}getRealIndex(e){return void 0===e&&(e=this.index),this.isShuffle?this.shuffled[e]:e}handle(e){let t=e.index;"waiting"!==e.status&&(this.list[t].id3=e,this.timeout&&window.clearTimeout(this.timeout),this.timeout=setTimeout(this.renderPagination.bind(this),100))}forceID3(e){let t=this;t.forceData||(t.forceData={},t.forceNotification=NotificationHandler.createNotification("TagReader -> 0 / "+t.list.length,"info",-1));let a=e.index;if("waiting"===e.status)return;t.list[a].id3=e,t.forceData[a]=!0;let i=Object.keys(t.forceData).length;this.forceNotification.updateMessageOnly("TagReader -> "+i+" / "+t.list.length),i===t.list.length&&t.forceNotification.remove()}}class GUI{async init(){this.data={},this.modal=new Modal,await template.loadArray(["playlist-item","playlist","playlist-footer","audio-information","inputs/color","inputs/input","inputs/slider","inputs/switch","inputs/select","inputs/option","help"]),this.initDropZone()}openHelp(){gui.modal.renderModal("Help",template.parseTemplate("help",{})),gui.modal.showModal()}initDropZone(){"drag dragstart dragend dragover dragenter dragleave drop".split(" ").forEach(e=>{window.addEventListener(e,async e=>{e.preventDefault(),e.stopPropagation(),"drop"===e.type&&(e.dataTransfer.files.length>0?(e.dataTransfer.id="upload-dir",player.playlist.changeFiles(e,e.dataTransfer)):alert("Sorry you need to upload files!"))})})}}class GUIHelper{static fromJSON(e,t){let a=[];for(let i of e)switch(i.type){case"slider":a.push(GUIHelper.createSliders(i,t));break;case"color":a.push(GUIHelper.createColorPicker(i,t));break;case"checkbox":a.push(GUIHelper.createCheckbox(i,t));break;case"input":a.push(GUIHelper.createInputField(i,t));break;case"select":a.push(GUIHelper.createSelect(i,t));break;case"button":a.push(GUIHelper.createButton(i,t));break;default:console.error("Unknown Type: "+i.type)}return a.join(" ")}static createSliders(e,t){let a="";if("object"==typeof e.name)for(let i=0;i${e.name}`}}class Modal{constructor(){this.currentModal="",this.modal=$("#modal"),this.parent=this.modal.parentNode,this.modal.addDelegatedEventListener("click","header .close",this.closeModal.bind(this))}resetModal(){this.renderModal("","","")}renderModal(e,t,a){$("#modal").removeClass("lightMode"),this.currentModal=e,this.renderHeader(e),this.renderContent(t),this.renderFooter(a)}renderHeader(e){$("header .headline",this.modal).innerHTML=e}renderContent(e){$("modal-content",this.modal).innerHTML=e}renderFooter(e){$("modal-footer .inner",this.modal).innerHTML=e||"by VersusTuneZ"}closeModal(){this.parent.addClass("hide")}isCurrent(e){return e===this.currentModal}showModal(){this.parent.removeClass("hide")}}class Visual{constructor(){this.data=[],this.dataArray=[],this.name="Default"}updateData(){}updateFFT(e){}draw(){}setup(){}}class VisualDrawer{constructor(){this.visuals={wave:new Wave,wave2d:new Wave2D},this.lastMainColor={base:"#-1",color:[0,0,0]},this.lastSecondColor={base:"#-1",color:[0,0,0]}}init(){this.switch(pConf.get("visual","wave2d")),this.updateLoop()}switch(e){null!=this.visuals[e]&&(this.c=e,vConf.loadConfigByName(this.c),this.visuals[this.c].setup(),pConf.set("visual",this.c),pConf.save())}updateLoop(){let e=this.visuals[this.c],t=shaderHandler.use(this.c);this.updateSeekbar(),this.prepare(t),e.updateData(),e.draw(t),requestAnimationFrame(this.updateLoop.bind(this))}updateSeekbar(){cInfo.width=window.innerWidth,cInfo.height=window.innerHeight;let e=audioHandler.audioFile;if(ctx.clearRect(0,0,cInfo.width,cInfo.height),!e.paused&&pConf.get("showSeekbar",!0)){let t=e.duration,a=e.currentTime/t*cInfo.width;ctx.fillStyle=pConf.get("seekColor","#fff"),ctx.fillRect(0,c.height-10,a,c.height)}}prepare(e){c.width=window.innerWidth,c.height=window.innerHeight,gl.viewport(0,0,gl.canvas.width,gl.canvas.height),gl.clearColor(0,0,0,parseFloat(pConf.get("alphaValue",0))),gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT),gl.enable(gl.DEPTH_TEST),gl.depthFunc(gl.LEQUAL),gl.enable(gl.CULL_FACE),this.setColor(e)}setColor(e){let t=gl.getUniformLocation(e,"u_baseColor"),a=gl.getUniformLocation(e,"u_maxColor"),i=this.lastMainColor,s=this.lastSecondColor;this.updateColor("lastMainColor","baseColor"),this.updateColor("lastSecondColor","gradientToColor"),gl.uniform3fv(t,i.color),gl.uniform3fv(a,s.color)}updateColor(e,t){let a=this[e],i=vConf.get(t,"#ffffff");i!==a.base&&(a.color=hexToRgb(i),a.base=i)}}class ImageUploader{async init(){this.image=pConf.get("bgURL",""),this.color=pConf.get("bgColour","#000000"),this.alpha=pConf.get("alphaValue",.5),this.getRealImage(),this.applyValues(),$("#modal").addDelegatedEventListener("change",'#image-upload input:not([type="color"])',this.changeHandler.bind(this)),$("#modal").addDelegatedEventListener("input","#image-upload input#color",this.changeHandler.bind(this))}async renderModal(){await template.loadTemplate("image"),gui.modal.resetModal(),gui.modal.renderModal("Background-Image",template.parseTemplate("image",{value:this.image,bgValue:this.color,alphaValue:this.alpha}),""),gui.modal.showModal()}changeHandler(e,t){"color"===t.id?this.color=t.value:"alphaValue"===t.id?this.alpha=t.value:(pConf.set("bgMode",t.id),"image"===t.id?(t.files[0].toBase64((e,t)=>{t?alert("Error converting image!"):(pConf.set("bgURL",e.currentTarget.result),pConf.save())}),this.image=URL.createObjectURL(t.files[0])):(this.image=t.value,pConf.set("bgURL",this.image))),pConf.set("bgColour",this.color),pConf.set("alphaValue",this.alpha),this.applyValues(),pConf.save()}applyValues(){let e=$("body");e.style.backgroundImage="url("+this.image+")",e.style.backgroundColor=this.color}getRealImage(){let e=pConf.get("bgMode"),t=pConf.get("bgURL","");if("image"===e){if(""!==t&&t.startsWith("data:image")){let e=t.split(";"),a=e.shift(),i=e.join(";").replace("base64,","");this.image=URL.createObjectURL(b64toBlob(i,a))}}else this.image=t}}const imageUploader=new ImageUploader;class NotificationHandler{static instance=new NotificationHandler;constructor(){this.outer=$(".notification"),this.notifications=[]}async init(){await template.loadTemplate("notification")}static createNotification(e,t,a){a=parseInt(a||"3000");let i=NotificationHandler.instance,s=new Notification(e,t,a);return i.notifications.push(s),s.show(),s}}class Notification{constructor(e,t,a){this.outer=NotificationHandler.instance.outer,this.message=e,this.type=t,this.time=a,this.isRemoved=!1}async show(){let e=this,t=-1===e.time;e.item=create("div"),e.item.addClass("notification-item, "+e.type),t&&(e.type+=" endless"),e.updateContent(e.message),this.outer.prepend(e.item),t||setTimeout(this.remove.bind(this),e.time)}async remove(){if(this.isRemoved)return;this.isRemoved=!0,this.outer.removeChild(this.item);let e=NotificationHandler.instance.notifications,t=e.indexOf(this);e.splice(t,1)}updateContent(e){let t={message:e,time:-1===this.time?1e3:this.time+1,type:this.type};this.item.innerHTML=template.parseTemplate("notification",t)}updateMessageOnly(e){let t=$(".message",this.item);t&&(t.innerHTML=e)}}class Config{static allConfigs={};constructor(e){this.config={},this.name="",this.type=e,Config.allConfigs[e]=this}loadConfigByName(e){this.save(),this.name="config-"+e;let t=localStorage.getItem(this.name);t&&(this.config=JSON.parse(t))}save(){""!==this.name&&localStorage.setItem(this.name,JSON.stringify(this.config))}set(e,t){this.config[e]=t}remove(e){delete this.config[e]}get(e,t){let a=this.config[e];return null==a&&(this.config[e]=t,a=t),a}reset(){NotificationHandler.createNotification("CONFIG REQUEST SUCCESS FOR "+this.type,"success",2e3),this.config={},this.save()}}class Sphere extends Visual{constructor(){super(),this.name="Sphere"}draw(){}setup(){}}class Wave extends Visual{constructor(){super(),this.name="3D Wave"}updateData(){let e=audioHandler.getFloatArray(),t=2/e.length,a=-1,i=0;for(let s=0;s "+e.message)}return!0}return!1}}async function initHandler(){let e=$("body");$(".playlist.menu-icon").addEventListener("click",e=>{player.playlist.renderPagination(player.playlist.page),gui.modal.showModal()}),e.addDelegatedEventListener("click",".playlist-item",(e,t)=>{let a=t.dataset.index;player.playByID(parseInt(a)),togglePlayButton("pause")}),e.addDelegatedEventListener("click",".controls button",(e,t)=>{switch(t.id){case"previous":player.prevSong();break;case"next":player.nextSong();break;case"play":player.playStop();break;case"shuffle":toggleShuffle()}}),window.addEventListener("playSong",setActiveOnPlaylist),window.addEventListener("playSong",e=>{togglePlayButton(audioHandler.audioFile.paused?"play":"pause")}),$(".upload-image").addEventListener("click",imageUploader.renderModal.bind(imageUploader)),e.addDelegatedEventListener("click",".readAll",forceAllRead),e.addDelegatedEventListener("input",'.input-range input[type="range"]',(e,t)=>{$(".current",t.parentNode).innerText=t.value}),e.addDelegatedEventListener("input",'input[type="color"]',(e,t)=>{$(".colorBlob",t.parentNode).style.backgroundColor=t.value}),e.addDelegatedEventListener("click",".visual-item",(e,t)=>{visual.switch(t.dataset.id||"wave"),$("modal-content .visuals .active").removeClass("active"),t.addClass("active")}),e.addDelegatedEventListener("input","section.base input",(e,t)=>{"checkbox"===t.type?pConf.set(t.name,t.checked):setValue(t.name,t.value,pConf,t.dataset.type),pConf.save()}),e.addDelegatedEventListener("input","section.visual input",(e,t)=>{"checkbox"===t.type?vConf.set(t.name,t.checked):setValue(t.name,t.value,vConf,t.dataset.type),vConf.save()}),e.addDelegatedEventListener("click",".button[data-action]",(e,t)=>{switch(t.dataset.action){case"resetVConf":vConf.reset(),setTimeout(e=>{playerConf.handleById()},30);break;case"makeModalTransparent":$("#modal").toggleClass("lightMode")}}),$(".help.menu-icon").addEventListener("click",gui.openHelp),document.onfullscreenchange=t=>{e.hasClass("fullscreen")?e.removeClass("fullscreen"):e.addClass("fullscreen")}}function forceAllRead(){let e=player.playlist.list;for(let t=0;t{t.dataset.name===e?t.removeClass("hide"):t.addClass("hide")})}!function(){const e=$("body");e.addDelegatedEventListener("click","custom-select .label",(e,t)=>{let a=t.parentNode,i=$$("custom-option",a),s=$("custom-options",a);if(a.hasClass("open"))s.style.maxHeight="",a.removeClass("open");else{let e=0;i.forEach((function(t){e+=t.offsetHeight})),s.style.maxHeight=e+"px",a.addClass("open")}}),e.addDelegatedEventListener("click","custom-select custom-option",(e,t)=>{let a=t.closest("custom-select"),i=$("input",a);$$("custom-option.active").forEach(e=>{e.removeClass("active")}),t.addClass("active"),i&&(i.value=t.dataset.value||t.innerText,$(".label",a).innerText=t.innerText,a.removeClass("open"),t.parentNode.style.maxHeight="",window.dispatchEvent(new CustomEvent("selectChanged",{detail:{select:a,event:a.dataset.event,value:i.value,name:i.name}})))}),window.addEventListener("selectChanged",e=>{"visualConf"===e.detail.event&&(e.preventDefault(),e.stopPropagation(),function(e){try{let t=e.value,a=Config.allConfigs[e.select.dataset.conf];"fftSize"===e.name&&(t=parseInt(e.value),visual.visuals[visual.c].updateFFT(t)),a.set(e.name,t),a.save()}catch(e){console.error(e)}}(e.detail))})}();class KeyHandler{async init(){await this.mediaKeys(),await this.addKeyHandler(),window.addEventListener("keydown",this.keyHandler.bind(this))}async mediaKeys(){if("mediaSession"in navigator){let e=navigator.mediaSession;e.setActionHandler("play",player.playStop.bind(player)),e.setActionHandler("pause",player.playStop.bind(player)),e.setActionHandler("previoustrack",player.prevSong.bind(player)),e.setActionHandler("nexttrack",player.prevSong.bind(player))}}async addKeyHandler(){eventHandler.addEvent("keys-Space",player.playStop.bind(player)),eventHandler.addEvent("keys-KeyN",player.nextSong.bind(player)),eventHandler.addEvent("keys-KeyV",player.prevSong.bind(player)),eventHandler.addEvent("keys-KeyS",playerConf.open.bind(playerConf)),eventHandler.addEvent("keys-KeyS-shift",toggleShuffle),eventHandler.addEvent("keys-KeyB",imageUploader.renderModal.bind(imageUploader)),eventHandler.addEvent("keys-KeyF-shift",forceAllRead),eventHandler.addEvent("keys-KeyH",gui.openHelp),eventHandler.addEvent("keys-KeyP",e=>{player.playlist.renderPagination(player.playlist.page),gui.modal.showModal()}),eventHandler.addEvent("keys-Escape, keys-KeyC-shift",e=>{gui.modal.resetModal(),gui.modal.closeModal()}),eventHandler.addEvent("keys-F11",e=>{document.fullscreenElement?document.exitFullscreen().catch(console.error):document.body.requestFullscreen().catch(console.error)})}async keyHandler(e){let t="keys-"+e.code+(e.shiftKey?"-shift":"")+(e.ctrlKey?"-ctrl":"");eventHandler.handleEvent({data:{cmd:t}})&&(e.preventDefault(),e.stopPropagation())}}class Startup{constructor(){this.modules={startup:!1,"id3-ready":!1}}moduleLoaded(e){this.modules[e]=!0,this.allModulesLoaded()}allModulesLoaded(){for(let e in this.modules)if(!this.modules[e])return!1;return window.dispatchEvent(new CustomEvent("startupFin")),!0}}const shaderHandler=new ShaderHandler(null),audioHandler=new AudioHandler,gui=new GUI,visual=new VisualDrawer,template=new Template,player=new Player,vConf=new Config("visual"),pConf=new Config("player"),worker=new Worker("/out/js/worker.min.js"),startup=new Startup,eventHandler=new EventHandler,playerConf=new PlayerConfigHandler,keyHandler=new KeyHandler;let c,gl,cInfo,ctx;async function startUP(){if(pConf.loadConfigByName("default"),c=$("#c"),gl=c.getContext("webgl2"),cInfo=$("#cInfo"),ctx=cInfo.getContext("2d"),!gl)return alert("SORRY THE BROWSER DOESN'T SUPPORT WEBGL2"),!1;shaderHandler.setGL(gl),await shaderHandler.loadArray(["wave","sphere","water","wave2d"],"shaders/"),await NotificationHandler.instance.init(),await audioHandler.init(),await player.init(),await visual.init(),await gui.init(),await imageUploader.init(),await playerConf.init(),await keyHandler.init(),await initHandler(),toggleShuffle(!1)}worker.addEventListener("message",e=>{"startup"!==e.data.status?eventHandler.handleEvent(e):startup.moduleLoaded(e.data.cmd)}),window.addEventListener("startupFin",e=>{setTimeout(e=>{$(".loading-screen").remove()},100)}),startUP().then(e=>{startup.moduleLoaded("startup")}); \ No newline at end of file diff --git a/out/theme/style.css b/out/theme/style.css index c24237e..474fa50 100644 --- a/out/theme/style.css +++ b/out/theme/style.css @@ -1 +1 @@ -@charset "UTF-8";*{box-sizing:border-box}:focus{outline:0}body,html{padding:0;margin:0;overflow:hidden;font-size:16px;font-family:sans-serif;background-color:#303030;background-repeat:no-repeat;background-position:center;background-size:cover;width:100vw;height:100vh}div{position:fixed;color:#fff;padding:1em}.hide{display:none!important}.icon{width:1em;height:1em;vertical-align:middle;font-size:1em;shape-rendering:geometricPrecision;transition:transform .5s cubic-bezier(.22,.61,.36,1);stroke-width:5px;text-align:center;display:block}::-webkit-scrollbar{width:3px;height:3px}::-webkit-scrollbar-button{width:15px;height:15px}::-webkit-scrollbar-thumb{background:#e1e1e1;border:0 none #fff;border-radius:100px}::-webkit-scrollbar-thumb:hover{background:#fff}::-webkit-scrollbar-thumb:active{background:#3949ab}::-webkit-scrollbar-track{background:#666;border:0 none #fff;border-radius:46px}::-webkit-scrollbar-track:hover{background:#666}::-webkit-scrollbar-track:active{background:#666}::-webkit-scrollbar-corner{background:0 0}canvas{position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none}group{display:block;padding-bottom:10px;user-select:none}group-label{display:block;border-bottom:1px solid #fff;font-size:21px;font-weight:500;user-select:none}group-input{display:flex;align-items:center;margin-top:5px;user-select:none}group-input label{padding-right:10px;user-select:none;width:150px}group-input input{flex-grow:1;user-select:none;max-width:150px}group-input button{border:1px solid #dcdcdc;background-color:transparent;color:#fff;margin-left:5px}.closed{transform:translateX(-350px);transition:all .5s}.top-menu-left{display:flex}.top-menu-left div{position:relative}.loading-screen{z-index:100;background-color:#000;width:100vw;height:100vh;display:flex;align-items:center;justify-content:center;flex-direction:column}.loading-screen span{font-family:monospace;font-size:4vw;z-index:2}.loading-screen loader{position:absolute;top:calc(6vw + 10px);left:0;right:0;bottom:0;margin:auto;display:block;width:30vw;height:6px;transform:scaleX(0);transform-origin:left;background-color:#3949ab;animation:loadingBar 2s infinite}.loading-screen loader.delay{background-color:rgba(0,110,168,.24);filter:blur(1px);animation-delay:.05s}@keyframes loadingBar{0%,100%{transform:scaleX(0) scaleY(0)}50%{transform:scaleX(1) scaleY(1);transform-origin:left}100%,51%{transform-origin:right}}.grey-screen{position:fixed;top:0;left:0;background-color:rgba(0,0,0,.5);width:100vw;height:100vh;display:flex;justify-content:center;align-items:center;z-index:100}.grey-screen.hide{display:none!important}modal-footer playlist{flex-direction:row-reverse;flex-wrap:wrap}modal-footer playlist .pagination{margin-left:auto}#image-upload form{display:flex;flex-direction:column;width:90%;margin:10px auto}.audio-item{display:flex;flex-direction:column}.audio-item .artist{font-size:.75em;color:#dcdcdc}.now-playing{font-size:.8em;display:block;margin-bottom:10px}.menus{z-index:10}.range{-webkit-appearance:none;width:100%;margin:5px 0}.range.center{margin-left:auto;margin-right:auto}.range.right{margin-left:10%}.range:focus{outline:0}.range::-webkit-slider-runnable-track{width:100%;height:5px;cursor:pointer;background:rgba(0,0,0,.12);border-radius:15px;border:none}.range::-webkit-slider-thumb{border:0 solid rgba(0,0,30,0);height:15px;width:15px;border-radius:15px;background:#ff0089;cursor:pointer;-webkit-appearance:none;margin-top:-5px}.range:focus::-webkit-slider-runnable-track{background:rgba(89,89,89,.12)}.range::-moz-range-track{width:100%;height:5px;cursor:pointer;background:rgba(0,0,0,.12);border-radius:15px;border:none}.range::-moz-range-thumb{border:0 solid rgba(0,0,30,0);height:15px;width:15px;border-radius:15px;background:#ff0089;cursor:pointer}.range::-ms-track{width:100%;height:5px;cursor:pointer;background:0 0;border-color:transparent;color:transparent}.range::-ms-fill-lower{background:rgba(0,0,0,.12);border:none;border-radius:30px}.range::-ms-fill-upper{background:rgba(0,0,0,.12);border:none;border-radius:30px}.range::-ms-thumb{border:0 solid rgba(0,0,30,0);height:15px;width:15px;border-radius:15px;background:#ff0089;cursor:pointer}.range:focus::-ms-fill-lower{background:rgba(0,0,0,.12)}.range:focus::-ms-fill-upper{background:rgba(89,89,89,.12)}.input{width:100%;position:relative;display:inline-block;margin-top:1rem;background-color:transparent}.input-range{margin-bottom:20px}input:focus+.input:after{width:100%}.input input:not([type=range]){border:none;border-bottom:2px solid #dcdcdc;position:relative;width:100%;background-color:transparent;padding:5px;color:#fff}.input input:not([type=range]):focus{outline:0}.input.center{margin-left:auto;margin-right:auto}.input.right{margin-left:10%}.input-label{display:none}.floating-label .input-label{display:block;position:absolute;top:0;transition:.4s cubic-bezier(.25,.8,.25,1);pointer-events:none;border-bottom:1px solid transparent}.floating-label input:focus~.input-label,.floating-label input:valid~.input-label{transform:translateY(-.72rem);color:#5ff507;font-size:.7rem}.floating-label input:valid~.input-label{transform:translateY(-.72rem);color:#ff0089;font-size:.7rem}.focus{content:'';width:0;background-color:#ff0089;position:absolute;bottom:0;left:0;right:0;margin:auto;height:2px;transition:.4s cubic-bezier(.8,.4,.25,1)}input:focus~.focus{width:100%}*{box-sizing:border-box}switch{display:flex;flex-direction:row;padding:5px}switch input{position:absolute;appearance:none;opacity:0}switch input:checked+label:after{transform:translateX(20px)}switch span{margin-left:10px}switch label{display:block;border-radius:10px;width:40px;height:20px;background-color:#dcdcdc;position:relative;cursor:pointer;padding:0}switch label:after{content:'';background-color:#3949ab;position:absolute;top:2px;left:2px;height:16px;width:16px;border-radius:10px;transition:.5s}input[type=file]{position:fixed;left:-100000vw;height:1px;width:1px}input[type=color]{opacity:0}.color-picker{position:relative}.color-picker input{position:absolute!important;top:0}.colorBlob{display:block;width:100%;height:20px;margin:5px 0}.button{text-align:center;user-select:none;border-radius:5px;border:1px solid #3949ab;padding:.5em 1em;cursor:pointer;transition:.5s}.button.spaced{margin-bottom:10px}.button:hover{border-color:#ff0089;border-radius:7px;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23)}.input .current,.input .max,.input .min{font-size:.8em;color:#ff0089;position:absolute;bottom:-1rem}.input .current{display:block;width:100%;text-align:center}.input .min{left:0}.input .max{right:0}custom-select{width:auto;min-width:200px;display:block}custom-select label{color:#ff0089;font-size:.7rem}custom-select input{display:none}custom-select .label{padding:10px 30px 10px 10px;cursor:pointer;position:relative;transition:all .3s;box-shadow:inset 0 0 3px #5e5e5e}custom-select .label::after{content:'';border:solid #dcdcdc;border-width:0 3px 3px 0;display:inline-block;padding:3px;transform:rotate(45deg);-webkit-transform:rotate(45deg);transition:all .3s ease-in-out;position:absolute;right:10px;top:calc(50% - 6px)}custom-select custom-options{max-height:0;overflow:hidden;transition:all .5s ease;font-size:.9em;display:block;border:1px solid transparent}custom-select custom-option{display:block;width:100%;padding:10px 5px;cursor:pointer;box-shadow:0 -1px 0 0 rgba(0,0,0,.08)}custom-select custom-option:hover{background-color:#3949ab;color:#fff}custom-select custom-option.active{font-weight:700}custom-select.open .label{background-color:rgba(0,0,0,.1)}custom-select.open .label::after{transform:rotate(-135deg);-webkit-transform:rotate(-135deg);top:calc(50% - 3px)}custom-select.open custom-options{max-height:none;border:1px solid #1b1b1b!important}.controls{right:0;display:flex}.controls button,.menu-icon{background-color:rgba(33,33,33,.6);border:none;font-size:1.4em;border-top:4px solid #3949ab;padding:1.5rem;cursor:pointer;color:#fff;transition:.5s}.controls button.active,.menu-icon.active{border-color:#ff0089}.controls button:hover,.menu-icon:hover{background-color:rgba(21,21,21,.7);border-color:#5ff507}playlist{display:flex;flex-direction:column}playlist div{padding:unset;position:unset}playlist .pagination{display:flex;justify-content:flex-end;font-size:1.5em;padding:5px}playlist .pagination .current{font-size:.9em}playlist .pagination .item{cursor:pointer;user-select:none;border-radius:5px;margin:0 3px;display:flex;align-items:center}playlist .pagination .item.inactive{color:#aaa;pointer-events:none;cursor:not-allowed}playlist .pagination .item:hover{color:#3949ab}playlist .playlist-item{display:flex;padding:5px;box-shadow:0 -1px 0 0 rgba(0,0,0,.08);cursor:pointer;transition:.5s}playlist .playlist-item.active{background-color:rgba(0,0,0,.2)}playlist .playlist-item.active .playlist-item-title:before{content:'🔊 ';padding-right:5px}playlist .playlist-item-title{margin-left:10px;padding:5px;display:flex;align-items:center}playlist .playlist-item-number{padding:5px 10px 5px 5px;width:50px;display:flex;align-items:center}playlist .playlist-item:hover{background-color:rgba(0,0,0,.4)}#modal{max-width:860px;width:90%;background-color:#303030;padding:unset;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);border-radius:15px;overflow:hidden}#modal.lightMode{background-color:rgba(0,0,0,.1)}#modal div{position:unset}#modal header{height:50px;font-size:30px;line-height:50px;padding-left:10px;overflow:hidden;background-color:#212121;display:flex;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23)}#modal header .headline{flex-grow:1}#modal header .close{margin-right:10px;font-size:24px;cursor:pointer}#modal header .close:hover{color:#3949ab}#modal modal-content{display:block;max-height:calc(100vh - 200px);overflow:auto}#modal modal-footer{display:block;box-shadow:0 -3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23)}#modal modal-footer .inner{padding:5px;width:calc(100% - 40px);margin:0 auto}.notification{right:10px;top:0;height:100%;display:flex;flex-direction:column-reverse;width:90%;max-width:400px;pointer-events:none}.notification .notification-item{margin-top:10px}.notification div{position:unset;padding:unset}.notification div.notification-item{position:relative}.notification-item{width:100%;border-radius:5px;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);overflow:hidden}.notification-item.success{background-color:rgba(74,177,11,.6)}.notification-item.error{background-color:rgba(255,50,50,.6)}.notification-item.warning{background-color:rgba(255,177,89,.6)}.notification-item.info{background-color:rgba(71,73,171,.6)}.notification-item .message{padding:1em}.notification-item .fade-bar{animation:fadeOut ease-in-out 3s;height:100%;width:100%;position:absolute;top:0;z-index:-1;opacity:.4;transform-origin:left}.notification-item .fade-bar:after{content:'';z-index:1;bottom:0;height:4px;width:100%;position:absolute;background-color:#fff}.notification-item .fade-bar.endless{animation:endlessFade ease-in-out .5s infinite}.notification-item .fade-bar.success{background-color:#60ff00}.notification-item .fade-bar.error{background-color:#fa0000}.notification-item .fade-bar.warning{background-color:#f70}.notification-item .fade-bar.info{background-color:#3949ab}@keyframes fadeOut{from{transform:scaleX(1)}to{transform:scaleX(0)}}@keyframes endlessFade{0%{transform:scaleX(1);transform-origin:right}49%{transform-origin:right}50%{transform:scaleX(0);transform-origin:left}100%{transform:scaleX(1)}}.config-nav{display:flex;flex-direction:row;background-color:#1b1b1b;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23)}.config-nav div{padding:10px 5px;cursor:pointer;user-select:none;border-bottom:1px solid transparent}.config-nav div.active{border-color:#5ff507}.config-nav div:hover{background-color:rgba(0,0,0,.4)}.config-content{padding:1em;min-height:200px}.config-content .visuals{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-around}.config-content .visuals .visual-item{display:flex;align-items:center;justify-content:center;padding:1em;min-width:100px;min-height:100px;background-color:#212121;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);transition:.5s;cursor:pointer}.config-content .visuals .visual-item:hover{background-color:#1b1b1b}.config-content .visuals .visual-item.active{border:1px solid #3949ab} \ No newline at end of file +@charset "UTF-8";*{box-sizing:border-box}:focus{outline:0}body,html{padding:0;margin:0;overflow:hidden;font-size:16px;font-family:sans-serif;background-color:#303030;background-repeat:no-repeat;background-position:center;background-size:cover;width:100vw;height:100vh}div{position:fixed;color:#fff;padding:1em}.hide{display:none!important}.icon{width:1em;height:1em;vertical-align:middle;font-size:1em;shape-rendering:geometricPrecision;transition:transform .5s cubic-bezier(.22,.61,.36,1);stroke-width:5px;text-align:center;display:block}::-webkit-scrollbar{width:3px;height:3px}::-webkit-scrollbar-button{width:15px;height:15px}::-webkit-scrollbar-thumb{background:#e1e1e1;border:0 none #fff;border-radius:100px}::-webkit-scrollbar-thumb:hover{background:#fff}::-webkit-scrollbar-thumb:active{background:#3949ab}::-webkit-scrollbar-track{background:#666;border:0 none #fff;border-radius:46px}::-webkit-scrollbar-track:hover{background:#666}::-webkit-scrollbar-track:active{background:#666}::-webkit-scrollbar-corner{background:0 0}canvas{position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none}group{display:block;padding-bottom:10px;user-select:none}group-label{display:block;border-bottom:1px solid #fff;font-size:21px;font-weight:500;user-select:none}group-input{display:flex;align-items:center;margin-top:5px;user-select:none}group-input label{padding-right:10px;user-select:none;width:150px}group-input input{flex-grow:1;user-select:none;max-width:150px}group-input button{border:1px solid #dcdcdc;background-color:transparent;color:#fff;margin-left:5px}.closed{transform:translateX(-350px);transition:all .5s}.top-menu-left{display:flex}.top-menu-left div{position:relative}.loading-screen{z-index:100;background-color:#000;width:100vw;height:100vh;display:flex;align-items:center;justify-content:center;flex-direction:column}.loading-screen span{font-family:monospace;font-size:4vw;z-index:2}.loading-screen loader{position:absolute;top:calc(6vw + 10px);left:0;right:0;bottom:0;margin:auto;display:block;width:30vw;height:6px;transform:scaleX(0);transform-origin:left;background-color:#3949ab;animation:loadingBar 2s infinite}.loading-screen loader.delay{background-color:rgba(0,110,168,.24);filter:blur(1px);animation-delay:.05s}@keyframes loadingBar{0%,100%{transform:scaleX(0) scaleY(0)}50%{transform:scaleX(1) scaleY(1);transform-origin:left}100%,51%{transform-origin:right}}.grey-screen{position:fixed;top:0;left:0;background-color:rgba(0,0,0,.5);width:100vw;height:100vh;display:flex;justify-content:center;align-items:center;z-index:100}.grey-screen.hide{display:none!important}modal-footer playlist{flex-direction:row-reverse;flex-wrap:wrap}modal-footer playlist .pagination{margin-left:auto}#image-upload form{display:flex;flex-direction:column;width:90%;margin:10px auto}.audio-item{display:flex;flex-direction:column}.audio-item .artist{font-size:.75em;color:#dcdcdc}.now-playing{font-size:.8em;display:block;margin-bottom:10px}.menus{z-index:10}body.fullscreen .menus{display:none}.help-list{display:flex;flex-direction:column}.help-list .item{padding:0 1em}.help-list .item:not(:last-child){border-bottom:1px solid #232323}.help-list .item .h2{font-size:1.2em;margin:10px 0 5px;display:block}.help-list .item p{font-size:.8em;color:#aaa}.range{-webkit-appearance:none;width:100%;margin:5px 0}.range.center{margin-left:auto;margin-right:auto}.range.right{margin-left:10%}.range:focus{outline:0}.range::-webkit-slider-runnable-track{width:100%;height:5px;cursor:pointer;background:rgba(0,0,0,.12);border-radius:15px;border:none}.range::-webkit-slider-thumb{border:0 solid rgba(0,0,30,0);height:15px;width:15px;border-radius:15px;background:#ff0089;cursor:pointer;-webkit-appearance:none;margin-top:-5px}.range:focus::-webkit-slider-runnable-track{background:rgba(89,89,89,.12)}.range::-moz-range-track{width:100%;height:5px;cursor:pointer;background:rgba(0,0,0,.12);border-radius:15px;border:none}.range::-moz-range-thumb{border:0 solid rgba(0,0,30,0);height:15px;width:15px;border-radius:15px;background:#ff0089;cursor:pointer}.range::-ms-track{width:100%;height:5px;cursor:pointer;background:0 0;border-color:transparent;color:transparent}.range::-ms-fill-lower{background:rgba(0,0,0,.12);border:none;border-radius:30px}.range::-ms-fill-upper{background:rgba(0,0,0,.12);border:none;border-radius:30px}.range::-ms-thumb{border:0 solid rgba(0,0,30,0);height:15px;width:15px;border-radius:15px;background:#ff0089;cursor:pointer}.range:focus::-ms-fill-lower{background:rgba(0,0,0,.12)}.range:focus::-ms-fill-upper{background:rgba(89,89,89,.12)}.input{width:100%;position:relative;display:inline-block;margin-top:1rem;background-color:transparent}.input-range{margin-bottom:20px}input:focus+.input:after{width:100%}.input input:not([type=range]){border:none;border-bottom:2px solid #dcdcdc;position:relative;width:100%;background-color:transparent;padding:5px;color:#fff}.input input:not([type=range]):focus{outline:0}.input.center{margin-left:auto;margin-right:auto}.input.right{margin-left:10%}.input-label{display:none}.floating-label .input-label{display:block;position:absolute;top:0;transition:.4s cubic-bezier(.25,.8,.25,1);pointer-events:none;border-bottom:1px solid transparent}.floating-label input:focus~.input-label,.floating-label input:valid~.input-label{transform:translateY(-.72rem);color:#5ff507;font-size:.7rem}.floating-label input:valid~.input-label{transform:translateY(-.72rem);color:#ff0089;font-size:.7rem}.focus{content:'';width:0;background-color:#ff0089;position:absolute;bottom:0;left:0;right:0;margin:auto;height:2px;transition:.4s cubic-bezier(.8,.4,.25,1)}input:focus~.focus{width:100%}*{box-sizing:border-box}switch{display:flex;flex-direction:row;padding:5px}switch input{position:absolute;appearance:none;opacity:0}switch input:checked+label:after{transform:translateX(20px)}switch span{margin-left:10px}switch label{display:block;border-radius:10px;width:40px;height:20px;background-color:#dcdcdc;position:relative;cursor:pointer;padding:0}switch label:after{content:'';background-color:#3949ab;position:absolute;top:2px;left:2px;height:16px;width:16px;border-radius:10px;transition:.5s}input[type=file]{position:fixed;left:-100000vw;height:1px;width:1px}input[type=color]{opacity:0}.color-picker{position:relative}.color-picker input{position:absolute!important;top:0}.colorBlob{display:block;width:100%;height:20px;margin:5px 0}.button{text-align:center;user-select:none;border-radius:5px;border:1px solid #3949ab;padding:.5em 1em;cursor:pointer;transition:.5s}.button.spaced{margin-bottom:10px}.button:hover{border-color:#ff0089;border-radius:7px;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23)}.input .current,.input .max,.input .min{font-size:.8em;color:#ff0089;position:absolute;bottom:-1rem}.input .current{display:block;width:100%;text-align:center}.input .min{left:0}.input .max{right:0}custom-select{width:auto;min-width:200px;display:block}custom-select label{color:#ff0089;font-size:.7rem}custom-select input{display:none}custom-select .label{padding:10px 30px 10px 10px;cursor:pointer;position:relative;transition:all .3s;box-shadow:inset 0 0 3px #5e5e5e}custom-select .label::after{content:'';border:solid #dcdcdc;border-width:0 3px 3px 0;display:inline-block;padding:3px;transform:rotate(45deg);-webkit-transform:rotate(45deg);transition:all .3s ease-in-out;position:absolute;right:10px;top:calc(50% - 6px)}custom-select custom-options{max-height:0;overflow:hidden;transition:all .5s ease;font-size:.9em;display:block;border:1px solid transparent}custom-select custom-option{display:block;width:100%;padding:10px 5px;cursor:pointer;box-shadow:0 -1px 0 0 rgba(0,0,0,.08)}custom-select custom-option:hover{background-color:#3949ab;color:#fff}custom-select custom-option.active{font-weight:700}custom-select.open .label{background-color:rgba(0,0,0,.1)}custom-select.open .label::after{transform:rotate(-135deg);-webkit-transform:rotate(-135deg);top:calc(50% - 3px)}custom-select.open custom-options{max-height:none;border:1px solid #1b1b1b!important}.controls{right:0;display:flex}.controls button,.menu-icon{background-color:rgba(33,33,33,.6);border:none;font-size:1.4em;border-top:4px solid #3949ab;padding:1.5rem;cursor:pointer;color:#fff;transition:.5s}.controls button.active,.menu-icon.active{border-color:#ff0089}.controls button:hover,.menu-icon:hover{background-color:rgba(21,21,21,.7);border-color:#5ff507}playlist{display:flex;flex-direction:column}playlist div{padding:unset;position:unset}playlist .playlist-content h1{padding:0 1em}playlist .pagination{display:flex;justify-content:flex-end;font-size:1.5em;padding:5px}playlist .pagination .current{font-size:.9em}playlist .pagination .item{cursor:pointer;user-select:none;border-radius:5px;margin:0 3px;display:flex;align-items:center}playlist .pagination .item.inactive{color:#aaa;pointer-events:none;cursor:not-allowed}playlist .pagination .item:hover{color:#3949ab}playlist .playlist-item{display:flex;padding:5px;box-shadow:0 -1px 0 0 rgba(0,0,0,.08);cursor:pointer;transition:.5s}playlist .playlist-item.active{background-color:rgba(0,0,0,.2)}playlist .playlist-item.active .playlist-item-title:before{content:'🔊 ';padding-right:5px}playlist .playlist-item-title{margin-left:10px;padding:5px;display:flex;align-items:center}playlist .playlist-item-number{padding:5px 10px 5px 5px;width:50px;display:flex;align-items:center}playlist .playlist-item:hover{background-color:rgba(0,0,0,.4)}#modal{max-width:860px;width:90%;background-color:#303030;padding:unset;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);border-radius:15px;overflow:hidden}#modal.lightMode{background-color:rgba(0,0,0,.1)}#modal div{position:unset}#modal header{height:50px;font-size:30px;line-height:50px;padding-left:10px;overflow:hidden;background-color:#212121;display:flex;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23)}#modal header .headline{flex-grow:1}#modal header .close{margin-right:10px;font-size:24px;cursor:pointer}#modal header .close:hover{color:#3949ab}#modal modal-content{display:block;max-height:calc(100vh - 200px);overflow:auto}#modal modal-footer{display:block;box-shadow:0 -3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23)}#modal modal-footer .inner{padding:5px;width:calc(100% - 40px);margin:0 auto}.notification{right:10px;top:0;height:100%;display:flex;flex-direction:column-reverse;width:90%;max-width:400px;pointer-events:none}.notification .notification-item{margin-top:10px}.notification div{position:unset;padding:unset}.notification div.notification-item{position:relative}.notification-item{width:100%;border-radius:5px;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);overflow:hidden}.notification-item.success{background-color:rgba(74,177,11,.6)}.notification-item.error{background-color:rgba(255,50,50,.6)}.notification-item.warning{background-color:rgba(255,177,89,.6)}.notification-item.info{background-color:rgba(71,73,171,.6)}.notification-item .message{padding:1em}.notification-item .fade-bar{animation:fadeOut ease-in-out 3s;height:100%;width:100%;position:absolute;top:0;z-index:-1;opacity:.4;transform-origin:left}.notification-item .fade-bar:after{content:'';z-index:1;bottom:0;height:4px;width:100%;position:absolute;background-color:#fff}.notification-item .fade-bar.endless{animation:endlessFade ease-in-out .5s infinite}.notification-item .fade-bar.success{background-color:#60ff00}.notification-item .fade-bar.error{background-color:#fa0000}.notification-item .fade-bar.warning{background-color:#f70}.notification-item .fade-bar.info{background-color:#3949ab}@keyframes fadeOut{from{transform:scaleX(1)}to{transform:scaleX(0)}}@keyframes endlessFade{0%{transform:scaleX(1);transform-origin:right}49%{transform-origin:right}50%{transform:scaleX(0);transform-origin:left}100%{transform:scaleX(1)}}.config-nav{display:flex;flex-direction:row;background-color:#1b1b1b;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23)}.config-nav div{padding:10px 5px;cursor:pointer;user-select:none;border-bottom:1px solid transparent}.config-nav div.active{border-color:#5ff507}.config-nav div:hover{background-color:rgba(0,0,0,.4)}.config-content{padding:1em;min-height:200px}.config-content .visuals{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-around}.config-content .visuals .visual-item{display:flex;align-items:center;justify-content:center;padding:1em;min-width:100px;min-height:100px;background-color:#212121;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);transition:.5s;cursor:pointer}.config-content .visuals .visual-item:hover{background-color:#1b1b1b}.config-content .visuals .visual-item.active{border:1px solid #3949ab} \ No newline at end of file diff --git a/out/tpl/help.tpl b/out/tpl/help.tpl new file mode 100644 index 0000000..8e1432a --- /dev/null +++ b/out/tpl/help.tpl @@ -0,0 +1,69 @@ + +
+
+ h +

+ Open Help Modal +

+
+
+ Space +

+ Switch between pause and play +

+
+
+ n +

+ Play next song +

+
+
+ v +

+ Play previous song +

+
+
+ s +

+ Open Settings Modal +

+
+
+ Shift + s +

+ Toggle Shuffle +

+
+
+ b +

+ Open background settings Modal +

+
+
+ Shift + f +

+ Force Song Tagger! +

+
+
+ p +

+ Show Playlist Modal +

+
+
+ ESC or Shift + C +

+ Close current open Modal +

+
+
+ F11 +

+ Toggle Fullscreen and hide GUI +

+
+
\ No newline at end of file diff --git a/out/tpl/image.tpl b/out/tpl/image.tpl index 2e2dd7a..f06a0d1 100644 --- a/out/tpl/image.tpl +++ b/out/tpl/image.tpl @@ -19,10 +19,11 @@ -