<main id="banksy">
    <header>
      <a href="https://medium.com/@leemartin/how-to-recreate-the-banksy-artwork-shredder-using-css-grid-ff20c0f5a19" target="blank">Read Tutorial on Medium</a>
    </header>
    
    <div id="piece" @click="$refs.art.click()">
      <div id="holder">
        <div id="painting">        
          <div id="shredded">
          <div class="shred"></div>
          <div class="shred"></div>
          <div class="shred"></div>
          <div class="shred"></div>
          <div class="shred"></div>
          <div class="shred"></div>
          <div class="shred"></div>
          <div class="shred"></div>
          <div class="shred"></div>
          <div class="shred"></div>
          <div class="shred"></div>
        </div>
          <div id="original"></div>
        </div>
      </div>
    <div id="frame"></div>    
  </div>
  <input ref="art" type="file" accept="image/*" @change="artSelected">
</main>
html, body, main{
  height: 100%;
  overflow: hidden;
  position: fixed;
  width: 100%;
}

main{
  align-items: center;
  display: flex;
  justify-content: center;
}

#piece{
  box-shadow: 0 0 20px 0 rgba(0,0,0,0.25);
  cursor: pointer;
  height: 50vh;
  max-height: 820px;
  position: relative;
  width: calc(50vh * 0.774);
}

#frame{
  background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/141041/banksy-frame.png);
  background-size: cover;
  height: 100%;
  position: absolute;
  width: 100%;
}

#holder{
  background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/141041/banksy-back.jpg);
  background-size: cover;
  height: calc(50vh * 0.69);
  left: 18.9%;
  position: absolute;
  top: 15.4%;
  width: calc(50vh * 0.774 * 0.617);
}

#painting{
  height: 100%;
  position: absolute;
  transform: translateY(0%);
  width: 100%;
}

#original, .shred{
  background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/141041/anne-painting.jpg);
  background-size: cover;
}

#original{
  height: 100%;
  position: absolute;
  top: 0;
  width: 100%;
}

#shredded{
  bottom: 0;
  display: grid;
  grid-column-gap: 3px;
  grid-template-columns: repeat(11, 1fr);
  height: 100%;
  position: absolute;
  width: 100%;
}

#shredded .shred{
  background-position: top center;
}

#shredded .shred:nth-child(1){
  background-position: 0% 0%;
}

#shredded .shred:nth-child(2){
  background-position: 10% 0%;
}

#shredded .shred:nth-child(3){
  background-position: 20% 0%;
}

#shredded .shred:nth-child(4){
  background-position: 30% 0%;
}

#shredded .shred:nth-child(5){
  background-position: 40% 0%;
}

#shredded .shred:nth-child(6){
  background-position: 50% 0%;
}

#shredded .shred:nth-child(7){
  background-position: 60% 0%;
}

#shredded .shred:nth-child(8){
  background-position: 70% 0%;
}

#shredded .shred:nth-child(9){
  background-position: 80% 0%;
}

#shredded .shred:nth-child(10){
  background-position: 90% 0%;
}

#shredded .shred:nth-child(11){
  background-position: 100% 0%;
}

input{
  display: none;
}

header{
  position: absolute;
  top: 2em;
}

header a{
  color: black;
}
const app = new Vue({
  el: '#banksy',
  data() {
    return {
      shredding: null,
      dropping: null
    }
  },
  methods: {
    shred() {
      this.shredding = anime({
        targets: '#original',
        height: 0,
        duration: 10000,
        easing: 'linear'
      })

      this.dropping = anime({
        targets: '#painting',
        translateY: '101%',
        duration: 10000,
        easing: 'linear'
      })
    },
    artSelected(e) {
      this.shredding.pause()
      this.dropping.pause()
      
      loadImage(
        e.target.files[0],
        canvas => {
          let url = canvas.toDataURL('image/jpeg')
          
          document.getElementById('original').style.backgroundImage = `url(${url})`
          
          let elements = Array.from(document.getElementsByClassName('shred'))
          
          elements.forEach(element => {
            element.style.backgroundImage = `url(${url})`
          })
          
          document.getElementById('original').style.height    = '100%'
          document.getElementById('painting').style.transform = 'translateY(0)'
          
          this.shred()
        }, {
          canvas: true,
          crop: true,
          maxHeight: 566,
          maxWidth: 392,
          orientation: true
        }
      )
    }
  },
  mounted() {
    this.shred()
  }
})

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js
  3. https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.19.0/load-image.all.min.js