Liveloop

An interactive timeline for social media. Every post is a tiny app you can play, save, and remix.

Product

  • Feed
  • Create
  • Claude Code plugin
  • Blog

Legal

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • DMCA

Project

  • Templates
© 2026 Liveloop. All rights reserved.
LiveloopVersion history

v1Current

@liveloop · 5/18/2026, 1:52:26 PM

Initial version — all lines are new.

+<style>
+ html,body{height:100%;margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:#070612;overflow:hidden;color:#e9d5ff;}
+ #wrap{position:relative;height:100%;width:100%;display:flex;flex-direction:column;}
+ #top{display:flex;align-items:center;justify-content:space-between;padding:.7rem .9rem .2rem;}
+ #top h1{margin:0;font-size:1rem;font-weight:900;letter-spacing:.03em;}
+ #ctrls{display:flex;gap:.4rem;align-items:center;padding:.4rem .9rem .6rem;}
+ #ctrls button{font:inherit;font-size:.78rem;font-weight:800;border:0;border-radius:9999px;padding:.4rem .7rem;background:rgba(255,255,255,.13);color:#e9d5ff;cursor:pointer;-webkit-tap-highlight-color:transparent;}
+ #play{background:linear-gradient(90deg,#22d3ee,#a855f7)!important;color:#fff!important;min-width:3.4rem;}
+ #tempo{font-size:.78rem;font-weight:800;opacity:.85;min-width:3.4rem;text-align:center;}
+ #grid{flex:1;display:block;width:100%;touch-action:none;}
+</style>
+<div id="wrap">
+ <div id="top"><h1>🎚️ Beat Grid</h1></div>
+ <div id="ctrls">
+ <button id="play" type="button">Play</button>
+ <button id="slow" type="button">–</button>
+ <span id="tempo">110 BPM</span>
+ <button id="fast" type="button">+</button>
+ <button id="clear" type="button">Clear</button>
+ </div>
+ <canvas id="grid"></canvas>
+</div>
+<script>
+(function(){
+ var LL=window.liveloop||null;
+ var cv=document.getElementById('grid'), ctx=cv.getContext('2d');
+ var playBtn=document.getElementById('play'), tempoEl=document.getElementById('tempo');
+ var STEPS=16, ROWS=5;
+ var NAMES=['Kick','Snare','Hat','Clap','Tom'];
+ var COLORS=['#fb7185','#fbbf24','#22d3ee','#a3e635','#c084fc'];
+ var pattern=[];
+ var W=0,H=0,dpr=1,labelW=0,stepW=0,rowH=0,gridTop=0;
+ var tempo=110, playing=false, ac=null;
+ var nextStepTime=0, schedStep=0, visStep=-1, schedQ=[], schedTimer=0;
+ var raf=0,running=false;
+
+ function defaultPattern(){
+ var p=[];
+ for(var r=0;r<ROWS;r++){ var row=[]; for(var s=0;s<STEPS;s++) row.push(0); p.push(row); }
+ [0,4,8,12].forEach(function(s){ p[0][s]=1; });
+ [4,12].forEach(function(s){ p[1][s]=1; });
+ [0,2,4,6,8,10,12,14].forEach(function(s){ p[2][s]=1; });
+ p[3][12]=1;
+ return p;
+ }
+ function setCanvas(){
+ var rc=cv.getBoundingClientRect();
+ W=Math.max(220,rc.width); H=Math.max(160,rc.height);
+ dpr=Math.min(window.devicePixelRatio||1,2.5);
+ cv.width=Math.round(W*dpr); cv.height=Math.round(H*dpr);
+ ctx.setTransform(dpr,0,0,dpr,0,0);
+ labelW=Math.round(W*0.17);
+ stepW=(W-labelW-W*0.02)/STEPS;
+ rowH=H/ROWS;
+ gridTop=0;
+ }
+ function noiseBuf(a,dur){
+ var n=Math.floor(a.sampleRate*dur), b=a.createBuffer(1,n,a.sampleRate), d=b.getChannelData(0);
+ for(var i=0;i<n;i++) d[i]=Math.random()*2-1;
+ return b;
+ }
+ function kick(a,t){
+ var o=a.createOscillator(),g=a.createGain();
+ o.frequency.setValueAtTime(155,t); o.frequency.exponentialRampToValueAtTime(48,t+0.12);
+ g.gain.setValueAtTime(1,t); g.gain.exponentialRampToValueAtTime(0.001,t+0.3);
+ o.connect(g).connect(a.destination); o.start(t); o.stop(t+0.32);
+ }
+ function snare(a,t){
+ var s=a.createBufferSource(); s.buffer=noiseBuf(a,0.2);
+ var hp=a.createBiquadFilter(); hp.type='highpass'; hp.frequency.value=1200;
+ var g=a.createGain(); g.gain.setValueAtTime(0.8,t); g.gain.exponentialRampToValueAtTime(0.001,t+0.18);
+ s.connect(hp).connect(g).connect(a.destination); s.start(t); s.stop(t+0.2);
+ var o=a.createOscillator(),og=a.createGain(); o.type='triangle'; o.frequency.value=190;
+ og.gain.setValueAtTime(0.45,t); og.gain.exponentialRampToValueAtTime(0.001,t+0.1);
+ o.connect(og).connect(a.destination); o.start(t); o.stop(t+0.11);
+ }
+ function hat(a,t){
+ var s=a.createBufferSource(); s.buffer=noiseBuf(a,0.05);
+ var hp=a.createBiquadFilter(); hp.type='highpass'; hp.frequency.value=7600;
+ var g=a.createGain(); g.gain.setValueAtTime(0.4,t); g.gain.exponentialRampToValueAtTime(0.001,t+0.05);
+ s.connect(hp).connect(g).connect(a.destination); s.start(t); s.stop(t+0.06);
+ }
+ function clap(a,t){
+ for(var k=0;k<3;k++){
+ var s=a.createBufferSource(); s.buffer=noiseBuf(a,0.09);
+ var bp=a.createBiquadFilter(); bp.type='bandpass'; bp.frequency.value=1600;
+ var g=a.createGain(), tt=t+k*0.02;
+ g.gain.setValueAtTime(0.5,tt); g.gain.exponentialRampToValueAtTime(0.001,tt+0.09);
+ s.connect(bp).connect(g).connect(a.destination); s.start(tt); s.stop(tt+0.1);
+ }
+ }
+ function tom(a,t){
+ var o=a.createOscillator(),g=a.createGain();
+ o.frequency.setValueAtTime(200,t); o.frequency.exponentialRampToValueAtTime(95,t+0.22);
+ g.gain.setValueAtTime(0.8,t); g.gain.exponentialRampToValueAtTime(0.001,t+0.28);
+ o.connect(g).connect(a.destination); o.start(t); o.stop(t+0.3);
+ }
+ var VOICES=[kick,snare,hat,clap,tom];
+ function trigger(r,t){ try{ VOICES[r](ac,t); }catch(e){} }
+ function stepDur(){ return 60/tempo/4; }
+ function scheduler(){
+ if(!ac||!playing) return;
+ while(nextStepTime < ac.currentTime+0.12){
+ for(var r=0;r<ROWS;r++) if(pattern[r][schedStep]) trigger(r,nextStepTime);
+ schedQ.push({s:schedStep,t:nextStepTime});
+ nextStepTime+=stepDur();
+ schedStep=(schedStep+1)%STEPS;
+ }
+ }
+ function startPlay(){
+ if(!ac){
+ var AC=window.AudioContext||window.webkitAudioContext;
+ if(!AC) return;
+ try{ ac=new AC(); }catch(e){ return; }
+ }
+ if(ac.state!=='running'&&ac.resume){ try{ ac.resume(); }catch(e){} }
+ playing=true; playBtn.textContent='Stop';
+ schedStep=0; visStep=-1; schedQ=[];
+ nextStepTime=ac.currentTime+0.06;
+ if(schedTimer) clearInterval(schedTimer);
+ schedTimer=setInterval(scheduler,25);
+ scheduler();
+ }
+ function stopPlay(){
+ playing=false; playBtn.textContent='Play'; visStep=-1;
+ if(schedTimer){ clearInterval(schedTimer); schedTimer=0; }
+ }
+ function save(){
+ if(LL&&LL.storage&&LL.storage.set){
+ try{ LL.storage.set({pattern:pattern,tempo:tempo}); }catch(e){}
+ }
+ }
+ function rr(x,y,w,h,rad){
+ var r=Math.min(rad,w/2,h/2);
+ ctx.beginPath();
+ ctx.moveTo(x+r,y);
+ ctx.arcTo(x+w,y,x+w,y+h,r);
+ ctx.arcTo(x+w,y+h,x,y+h,r);
+ ctx.arcTo(x,y+h,x,y,r);
+ ctx.arcTo(x,y,x+w,y,r);
+ ctx.closePath();
+ }
+ function render(){
+ ctx.fillStyle='#070612'; ctx.fillRect(0,0,W,H);
+ if(playing&&ac){
+ while(schedQ.length && schedQ[0].t<=ac.currentTime){ visStep=schedQ[0].s; schedQ.shift(); }
+ }
+ for(var r=0;r<ROWS;r++){
+ var y=r*rowH;
+ ctx.fillStyle=COLORS[r];
+ ctx.font='800 '+Math.round(rowH*0.2)+'px system-ui';
+ ctx.textAlign='left'; ctx.textBaseline='middle';
+ ctx.fillText(NAMES[r],W*0.03,y+rowH/2);
+ for(var s=0;s<STEPS;s++){
+ var x=labelW+s*stepW;
+ var beat=Math.floor(s/4)%2===0;
+ var on=pattern[r][s];
+ var cx=x+stepW*0.5, cy=y+rowH*0.5;
+ var w=stepW*0.78, h=rowH*0.62;
+ if(s===visStep){
+ ctx.fillStyle='rgba(255,255,255,0.1)';
+ ctx.fillRect(x,y,stepW,rowH);
+ }
+ ctx.fillStyle=on?COLORS[r]:(beat?'rgba(255,255,255,0.09)':'rgba(255,255,255,0.045)');
+ rr(cx-w/2,cy-h/2,w,h,Math.min(w,h)*0.28); ctx.fill();
+ if(on){
+ ctx.fillStyle='rgba(255,255,255,0.3)';
+ rr(cx-w/2+w*0.16,cy-h/2+h*0.14,w*0.68,h*0.22,h*0.1); ctx.fill();
+ }
+ }
+ }
+ }
+ function frame(){
+ if(!running) return;
+ render();
+ raf=requestAnimationFrame(frame);
+ }
+ function startLoop(){ if(running)return; running=true; raf=requestAnimationFrame(frame); }
+ function stopLoop(){ running=false; if(raf)cancelAnimationFrame(raf); raf=0; }
+ function cellAt(px,py){
+ if(px<labelW) return null;
+ var s=Math.floor((px-labelW)/stepW), r=Math.floor(py/rowH);
+ if(s<0||s>=STEPS||r<0||r>=ROWS) return null;
+ return {r:r,s:s};
+ }
+ cv.addEventListener('pointerdown',function(e){
+ var rc=cv.getBoundingClientRect();
+ var c=cellAt(e.clientX-rc.left,e.clientY-rc.top);
+ if(!c) return;
+ pattern[c.r][c.s]=pattern[c.r][c.s]?0:1;
+ if(pattern[c.r][c.s] && ac && ac.state==='running') trigger(c.r,ac.currentTime+0.01);
+ save();
+ });
+ playBtn.addEventListener('click',function(){ if(playing) stopPlay(); else startPlay(); });
+ document.getElementById('slow').addEventListener('click',function(){
+ tempo=Math.max(60,tempo-10); tempoEl.textContent=tempo+' BPM'; save();
+ });
+ document.getElementById('fast').addEventListener('click',function(){
+ tempo=Math.min(190,tempo+10); tempoEl.textContent=tempo+' BPM'; save();
+ });
+ document.getElementById('clear').addEventListener('click',function(){
+ for(var r=0;r<ROWS;r++) for(var s=0;s<STEPS;s++) pattern[r][s]=0;
+ save();
+ });
+ function onResize(){ setCanvas(); }
+ window.addEventListener('resize',onResize);
+ if(LL && LL.onResize) LL.onResize(onResize);
+ if(LL && LL.onVisibility) LL.onVisibility(function(v){
+ if(!v && playing) stopPlay();
+ if(v) startLoop(); else stopLoop();
+ });
+ document.addEventListener('visibilitychange',function(){
+ if(document.hidden){ if(playing) stopPlay(); stopLoop(); } else startLoop();
+ });
+
+ pattern=defaultPattern();
+ setCanvas();
+ tempoEl.textContent=tempo+' BPM';
+ if(LL&&LL.storage&&LL.storage.get){
+ LL.storage.get().then(function(s){
+ if(s){
+ if(s.pattern&&s.pattern.length===ROWS){
+ var ok=true;
+ for(var r=0;r<ROWS;r++) if(!s.pattern[r]||s.pattern[r].length!==STEPS) ok=false;
+ if(ok) pattern=s.pattern;
+ }
+ if(typeof s.tempo==='number'&&s.tempo>=60&&s.tempo<=190){
+ tempo=s.tempo; tempoEl.textContent=tempo+' BPM';
+ }
+ }
+ },function(){});
+ }
+ startLoop();
+})();
+</script>

v1Current

@liveloop · 5/18/2026, 1:52:26 PM

Initial version — all lines are new.

+<style>
+ html,body{height:100%;margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:#070612;overflow:hidden;color:#e9d5ff;}
+ #wrap{position:relative;height:100%;width:100%;display:flex;flex-direction:column;}
+ #top{display:flex;align-items:center;justify-content:space-between;padding:.7rem .9rem .2rem;}
+ #top h1{margin:0;font-size:1rem;font-weight:900;letter-spacing:.03em;}
+ #ctrls{display:flex;gap:.4rem;align-items:center;padding:.4rem .9rem .6rem;}
+ #ctrls button{font:inherit;font-size:.78rem;font-weight:800;border:0;border-radius:9999px;padding:.4rem .7rem;background:rgba(255,255,255,.13);color:#e9d5ff;cursor:pointer;-webkit-tap-highlight-color:transparent;}
+ #play{background:linear-gradient(90deg,#22d3ee,#a855f7)!important;color:#fff!important;min-width:3.4rem;}
+ #tempo{font-size:.78rem;font-weight:800;opacity:.85;min-width:3.4rem;text-align:center;}
+ #grid{flex:1;display:block;width:100%;touch-action:none;}
+</style>
+<div id="wrap">
+ <div id="top"><h1>🎚️ Beat Grid</h1></div>
+ <div id="ctrls">
+ <button id="play" type="button">Play</button>
+ <button id="slow" type="button">–</button>
+ <span id="tempo">110 BPM</span>
+ <button id="fast" type="button">+</button>
+ <button id="clear" type="button">Clear</button>
+ </div>
+ <canvas id="grid"></canvas>
+</div>
+<script>
+(function(){
+ var LL=window.liveloop||null;
+ var cv=document.getElementById('grid'), ctx=cv.getContext('2d');
+ var playBtn=document.getElementById('play'), tempoEl=document.getElementById('tempo');
+ var STEPS=16, ROWS=5;
+ var NAMES=['Kick','Snare','Hat','Clap','Tom'];
+ var COLORS=['#fb7185','#fbbf24','#22d3ee','#a3e635','#c084fc'];
+ var pattern=[];
+ var W=0,H=0,dpr=1,labelW=0,stepW=0,rowH=0,gridTop=0;
+ var tempo=110, playing=false, ac=null;
+ var nextStepTime=0, schedStep=0, visStep=-1, schedQ=[], schedTimer=0;
+ var raf=0,running=false;
+
+ function defaultPattern(){
+ var p=[];
+ for(var r=0;r<ROWS;r++){ var row=[]; for(var s=0;s<STEPS;s++) row.push(0); p.push(row); }
+ [0,4,8,12].forEach(function(s){ p[0][s]=1; });
+ [4,12].forEach(function(s){ p[1][s]=1; });
+ [0,2,4,6,8,10,12,14].forEach(function(s){ p[2][s]=1; });
+ p[3][12]=1;
+ return p;
+ }
+ function setCanvas(){
+ var rc=cv.getBoundingClientRect();
+ W=Math.max(220,rc.width); H=Math.max(160,rc.height);
+ dpr=Math.min(window.devicePixelRatio||1,2.5);
+ cv.width=Math.round(W*dpr); cv.height=Math.round(H*dpr);
+ ctx.setTransform(dpr,0,0,dpr,0,0);
+ labelW=Math.round(W*0.17);
+ stepW=(W-labelW-W*0.02)/STEPS;
+ rowH=H/ROWS;
+ gridTop=0;
+ }
+ function noiseBuf(a,dur){
+ var n=Math.floor(a.sampleRate*dur), b=a.createBuffer(1,n,a.sampleRate), d=b.getChannelData(0);
+ for(var i=0;i<n;i++) d[i]=Math.random()*2-1;
+ return b;
+ }
+ function kick(a,t){
+ var o=a.createOscillator(),g=a.createGain();
+ o.frequency.setValueAtTime(155,t); o.frequency.exponentialRampToValueAtTime(48,t+0.12);
+ g.gain.setValueAtTime(1,t); g.gain.exponentialRampToValueAtTime(0.001,t+0.3);
+ o.connect(g).connect(a.destination); o.start(t); o.stop(t+0.32);
+ }
+ function snare(a,t){
+ var s=a.createBufferSource(); s.buffer=noiseBuf(a,0.2);
+ var hp=a.createBiquadFilter(); hp.type='highpass'; hp.frequency.value=1200;
+ var g=a.createGain(); g.gain.setValueAtTime(0.8,t); g.gain.exponentialRampToValueAtTime(0.001,t+0.18);
+ s.connect(hp).connect(g).connect(a.destination); s.start(t); s.stop(t+0.2);
+ var o=a.createOscillator(),og=a.createGain(); o.type='triangle'; o.frequency.value=190;
+ og.gain.setValueAtTime(0.45,t); og.gain.exponentialRampToValueAtTime(0.001,t+0.1);
+ o.connect(og).connect(a.destination); o.start(t); o.stop(t+0.11);
+ }
+ function hat(a,t){
+ var s=a.createBufferSource(); s.buffer=noiseBuf(a,0.05);
+ var hp=a.createBiquadFilter(); hp.type='highpass'; hp.frequency.value=7600;
+ var g=a.createGain(); g.gain.setValueAtTime(0.4,t); g.gain.exponentialRampToValueAtTime(0.001,t+0.05);
+ s.connect(hp).connect(g).connect(a.destination); s.start(t); s.stop(t+0.06);
+ }
+ function clap(a,t){
+ for(var k=0;k<3;k++){
+ var s=a.createBufferSource(); s.buffer=noiseBuf(a,0.09);
+ var bp=a.createBiquadFilter(); bp.type='bandpass'; bp.frequency.value=1600;
+ var g=a.createGain(), tt=t+k*0.02;
+ g.gain.setValueAtTime(0.5,tt); g.gain.exponentialRampToValueAtTime(0.001,tt+0.09);
+ s.connect(bp).connect(g).connect(a.destination); s.start(tt); s.stop(tt+0.1);
+ }
+ }
+ function tom(a,t){
+ var o=a.createOscillator(),g=a.createGain();
+ o.frequency.setValueAtTime(200,t); o.frequency.exponentialRampToValueAtTime(95,t+0.22);
+ g.gain.setValueAtTime(0.8,t); g.gain.exponentialRampToValueAtTime(0.001,t+0.28);
+ o.connect(g).connect(a.destination); o.start(t); o.stop(t+0.3);
+ }
+ var VOICES=[kick,snare,hat,clap,tom];
+ function trigger(r,t){ try{ VOICES[r](ac,t); }catch(e){} }
+ function stepDur(){ return 60/tempo/4; }
+ function scheduler(){
+ if(!ac||!playing) return;
+ while(nextStepTime < ac.currentTime+0.12){
+ for(var r=0;r<ROWS;r++) if(pattern[r][schedStep]) trigger(r,nextStepTime);
+ schedQ.push({s:schedStep,t:nextStepTime});
+ nextStepTime+=stepDur();
+ schedStep=(schedStep+1)%STEPS;
+ }
+ }
+ function startPlay(){
+ if(!ac){
+ var AC=window.AudioContext||window.webkitAudioContext;
+ if(!AC) return;
+ try{ ac=new AC(); }catch(e){ return; }
+ }
+ if(ac.state!=='running'&&ac.resume){ try{ ac.resume(); }catch(e){} }
+ playing=true; playBtn.textContent='Stop';
+ schedStep=0; visStep=-1; schedQ=[];
+ nextStepTime=ac.currentTime+0.06;
+ if(schedTimer) clearInterval(schedTimer);
+ schedTimer=setInterval(scheduler,25);
+ scheduler();
+ }
+ function stopPlay(){
+ playing=false; playBtn.textContent='Play'; visStep=-1;
+ if(schedTimer){ clearInterval(schedTimer); schedTimer=0; }
+ }
+ function save(){
+ if(LL&&LL.storage&&LL.storage.set){
+ try{ LL.storage.set({pattern:pattern,tempo:tempo}); }catch(e){}
+ }
+ }
+ function rr(x,y,w,h,rad){
+ var r=Math.min(rad,w/2,h/2);
+ ctx.beginPath();
+ ctx.moveTo(x+r,y);
+ ctx.arcTo(x+w,y,x+w,y+h,r);
+ ctx.arcTo(x+w,y+h,x,y+h,r);
+ ctx.arcTo(x,y+h,x,y,r);
+ ctx.arcTo(x,y,x+w,y,r);
+ ctx.closePath();
+ }
+ function render(){
+ ctx.fillStyle='#070612'; ctx.fillRect(0,0,W,H);
+ if(playing&&ac){
+ while(schedQ.length && schedQ[0].t<=ac.currentTime){ visStep=schedQ[0].s; schedQ.shift(); }
+ }
+ for(var r=0;r<ROWS;r++){
+ var y=r*rowH;
+ ctx.fillStyle=COLORS[r];
+ ctx.font='800 '+Math.round(rowH*0.2)+'px system-ui';
+ ctx.textAlign='left'; ctx.textBaseline='middle';
+ ctx.fillText(NAMES[r],W*0.03,y+rowH/2);
+ for(var s=0;s<STEPS;s++){
+ var x=labelW+s*stepW;
+ var beat=Math.floor(s/4)%2===0;
+ var on=pattern[r][s];
+ var cx=x+stepW*0.5, cy=y+rowH*0.5;
+ var w=stepW*0.78, h=rowH*0.62;
+ if(s===visStep){
+ ctx.fillStyle='rgba(255,255,255,0.1)';
+ ctx.fillRect(x,y,stepW,rowH);
+ }
+ ctx.fillStyle=on?COLORS[r]:(beat?'rgba(255,255,255,0.09)':'rgba(255,255,255,0.045)');
+ rr(cx-w/2,cy-h/2,w,h,Math.min(w,h)*0.28); ctx.fill();
+ if(on){
+ ctx.fillStyle='rgba(255,255,255,0.3)';
+ rr(cx-w/2+w*0.16,cy-h/2+h*0.14,w*0.68,h*0.22,h*0.1); ctx.fill();
+ }
+ }
+ }
+ }
+ function frame(){
+ if(!running) return;
+ render();
+ raf=requestAnimationFrame(frame);
+ }
+ function startLoop(){ if(running)return; running=true; raf=requestAnimationFrame(frame); }
+ function stopLoop(){ running=false; if(raf)cancelAnimationFrame(raf); raf=0; }
+ function cellAt(px,py){
+ if(px<labelW) return null;
+ var s=Math.floor((px-labelW)/stepW), r=Math.floor(py/rowH);
+ if(s<0||s>=STEPS||r<0||r>=ROWS) return null;
+ return {r:r,s:s};
+ }
+ cv.addEventListener('pointerdown',function(e){
+ var rc=cv.getBoundingClientRect();
+ var c=cellAt(e.clientX-rc.left,e.clientY-rc.top);
+ if(!c) return;
+ pattern[c.r][c.s]=pattern[c.r][c.s]?0:1;
+ if(pattern[c.r][c.s] && ac && ac.state==='running') trigger(c.r,ac.currentTime+0.01);
+ save();
+ });
+ playBtn.addEventListener('click',function(){ if(playing) stopPlay(); else startPlay(); });
+ document.getElementById('slow').addEventListener('click',function(){
+ tempo=Math.max(60,tempo-10); tempoEl.textContent=tempo+' BPM'; save();
+ });
+ document.getElementById('fast').addEventListener('click',function(){
+ tempo=Math.min(190,tempo+10); tempoEl.textContent=tempo+' BPM'; save();
+ });
+ document.getElementById('clear').addEventListener('click',function(){
+ for(var r=0;r<ROWS;r++) for(var s=0;s<STEPS;s++) pattern[r][s]=0;
+ save();
+ });
+ function onResize(){ setCanvas(); }
+ window.addEventListener('resize',onResize);
+ if(LL && LL.onResize) LL.onResize(onResize);
+ if(LL && LL.onVisibility) LL.onVisibility(function(v){
+ if(!v && playing) stopPlay();
+ if(v) startLoop(); else stopLoop();
+ });
+ document.addEventListener('visibilitychange',function(){
+ if(document.hidden){ if(playing) stopPlay(); stopLoop(); } else startLoop();
+ });
+
+ pattern=defaultPattern();
+ setCanvas();
+ tempoEl.textContent=tempo+' BPM';
+ if(LL&&LL.storage&&LL.storage.get){
+ LL.storage.get().then(function(s){
+ if(s){
+ if(s.pattern&&s.pattern.length===ROWS){
+ var ok=true;
+ for(var r=0;r<ROWS;r++) if(!s.pattern[r]||s.pattern[r].length!==STEPS) ok=false;
+ if(ok) pattern=s.pattern;
+ }
+ if(typeof s.tempo==='number'&&s.tempo>=60&&s.tempo<=190){
+ tempo=s.tempo; tempoEl.textContent=tempo+' BPM';
+ }
+ }
+ },function(){});
+ }
+ startLoop();
+})();
+</script>
← Version history