JSFiddle - React, Tailwind, and code Playground

by pleinx

HTML

<!--
design by: https://www.behance.net/vahanhovh
-->
<nav>
  <div class="controls">
    Backing track: Shuffle Blues in A
    <a class="rewind">
      <svg width="26" height="16" viewBox="160 18 26 16" xmlns="http://www.w3.org/2000/svg" class="rewind-icon"><path d="M173.3 26.143l12 6.857V18.778l-12 6.857v-6.857l-12.444 7.11L173.3 33v-6.857z" fill="#A8B5C3" fill-rule="evenodd"/></svg>
    </a>
    <a class="play">
      <svg width="21" height="24" viewBox="210 14 21 24" xmlns="http://www.w3.org/2000/svg" class="play-icon"><path fill="#A8B5C2" fill-rule="evenodd" d="M230.677 25.815L210 37.63V14"/></svg>
      <svg width="21px" height="24px" viewBox="210 14 21 24" xmlns="http://www.w3.org/2000/svg" class="pause-icon">
      <rect id="pause-1" fill="#A8B5C2" fill-rule="evenodd" x="210" y="14" width="7" height="24"></rect>
      <rect id="pause-2"  fill="#A8B5C2" fill-rule="evenodd" x="224" y="14" width="7" height="24"></rect>
    </svg>
    </a>
  </div>
  <div class="social">
    <a href="//www.reddit.com/submit?url=http://codepen.io/gregh/full/zNzvOm/" target="_blank"><i class="fa fa-reddit-alien" aria-hidden="true"></i></a>
    <a href="https://twitter.com/intent/tweet?text=Everyone%20can%20play%20the%20blues%20on%20@codepen!%20Record%20your%20solos%20and%20@greghvns%20will%20play%20the%20best%20ones%20on%20a%20real%20guitar&url=http://codepen.io/gregh/full/zNzvOm/" target="_blank"><i class="fa fa-twitter" aria-hidden="true"></i></a>
  </div>
</nav>

<div class="loading">
  <svg xmlns="http://www.w3.org/2000/svg" width="468" height="153" viewBox="166 91 468 153" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <path id="a" d="M55.185 12.262c-.347.79-.546 1.666-.546 2.62 0 4.574-7.84 53.744-7.84 58.546 0 4.8-2.533 11.727 0 11.727 2.534 0 7.29 1.25 11.385-4.788 4.097-6.037 17.77-29.975 19.23-29.975 1.457 0-7.587 28.44-.427 29.975 4.607.99 11.635-3.858 16.48-8.035.96 5.18 4.9 8.22 13.818 8.22 12.986 0 22.383-13.286 22.383-13.286s.418-3.898-5.88 0c-6.298...

CSS

nav {
  background-color: #221C44;
  height: 52px;
  font-family: 'Roboto', sans-serif;
  color: #969DA2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 40px;
  font-size: 14px;
  line-height: 17px;
  position: relative;
  z-index: 2;
  .rewind {
    margin-left: 28px;
    height: 16px;
    cursor: pointer;
  }
  .play {
    margin-left: 24px;
    height: 24px;
    cursor: pointer;
  }
  .play-icon, 
  .rewind-icon, 
  .pause-icon {
    &:hover path,
    &:hover rect {
      fill: #566574;
    }
  }
  .pause-icon {
    display: none;
  }
  .controls {
    display: flex;
    align-items: center;
  }
  .social a {
    font-size: 24px;
    color: #A8B5C2;
    margin-left: 18px;
    &:hover {
      color: #566574;
    }
  }
}

.loading {
  display: flex;
  justify-content: center;
  margin-top: 24px;
  .progress {
    transition: width 0.3s linear;
  }
  position: relative;
  z-index: 1;
}

.notes {
  display: flex;
  height: 0;
  opacity: 0;
  transition: opacity 1s ease;
  justify-content: center;
  position: relative;
  z-index: 2;
  overflow: hidden;
  .note {
    & > div {
      height: 100%;
      width: 32px;
      border-radius: 16px;
      background-color: #D8D8D8;
      color: #541F5D;
      font-family: 'Roboto', sans-serif;
      font-size: 20px;
      font-weight: 700;
      line-height: 23px;
      text-align: center;
      box-sizing: border-box;
      padding: 5px 0;
      box-shadow: 0 7px 8px rgba(0, 0, 0, .16); 
    }
    &:hover div {
      background-color: #FF6545;
      color: #fff;
    }
    height: 132px;
    &.key{
      height: 172px;
      & > div {
        background-color: #ECDCCA; 
      }    
      &:hover > div {
        background-color: #FF6545;
        color: #fff;
      }
    }     
    &:not(:first-child) > div {
      margin-left: 8px;
    }
    &:not(:last-child) > div {
      margin-right: 8px;
    }
    span {
      font-size: 0.7em;
    }
  }
}

.guitar {
  width: 96%;
  min-width:...

Babel + JSX

class Guitar {
  
  constructor(context, buffer) {
    this.context = context;
    this.buffer = buffer;
  }
  
  setup() {
    this.gainNode = this.context.createGain();
    this.source = this.context.createBufferSource();
    this.source.buffer = this.buffer;
    this.source.connect(this.gainNode);
    this.gainNode.connect(this.context.destination);
    
    this.gainNode.gain.value = 0.8;
  }

  play() {
    this.setup();
    this.source.start(this.context.currentTime);
  }
  
  stop() {
    this.gainNode.gain.exponentialRampToValueAtTime(0.001, this.context.currentTime + 0.5);
    this.source.stop(this.context.currentTime + 0.5);
  }
  
}

class Buffer {
  
  constructor(context, urls) {  
    this.context = context;
    this.urls = urls;
    this.buffer = [];
  }
  
  loadSound(url, index) {
    let request = new XMLHttpRequest();
    request.open('get', url, true);
    request.responseType = 'arraybuffer';
    let thisBuffer = this;
    request.onload = function() {
      // Safari doesn't support promise based syntax
      thisBuffer.context
        .decodeAudioData(request.response, function(buffer) {
          thisBuffer.buffer[index] = buffer;
          updateProgress(thisBuffer.urls.length);
          if(index == thisBuffer.urls.length-1) {
            thisBuffer.loaded();
          }       
        });
    };
    request.send();
  };
  
  getBuffer() {
    this.urls.forEach((url, index) => {
      this.loadSound(url, index);
    })
  }
  
  loaded() {
    document.querySelector('.loading').style.opacity = 0;
    document.querySelector('.loading').style.height = 0;
    document.querySelector('.notes').style.height = "auto";
    document.querySelector('.notes').style.opacity = 1;
    loaded = true;
    
    starWars();
  }
  
  getSound(index) {
    return this.buffer[index];
  }

}

function playNote() {
  let sound = new Sound(context);
  let value = this.dataset.frequency;
  sound.play(value);
  sound.stop();
}

let progressBar =...