<div class="container">
  <!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In  -->
<svg class="heartSVG" version="1.1"
	 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
	 x="0px" y="0px" width="800" height="800" viewBox="0 0 800 800" >
<defs>
  <path id="heart" stroke="none" class="particle" d="M7.3,0C6.3,0,5.5,0.5,5,1.2C4.5,0.5,3.7,0,2.8,0C1.2,0,0,1.2,0,2.8C0,6.5,3.9,10,5,10
	s5-3.5,5-7.3C10,1.2,8.8,0,7.3,0z"/>
  <!-- <circle id="dot" fill="none" stroke-width="1" class="particle" cx="4" cy="4" r="2"/> -->
   <path id="dot" fill="none" stroke-width="1" class="particle" d="M7.3,0C6.3,0,5.5,0.5,5,1.2C4.5,0.5,3.7,0,2.8,0C1.2,0,0,1.2,0,2.8C0,6.5,3.9,10,5,10
	s5-3.5,5-7.3C10,1.2,8.8,0,7.3,0z"/>
 <circle id="ring"  fill="none" class="ring" cx="4" cy="4" r="30"/>


</defs>
<g class="pContainer">
  </g>

</svg>

  
</div>
body {
  background-color:#000;
  overflow:hidden;
}

body,
html {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
}
.container{
  position:absolute;
  width:100%;
  height:100%;
 
}

svg{
  visibility:hidden;
  overflow:visible;
 
}

.particle{
  /*mix-blend-mode:overlay;*/
}

.ring{
  vector-effect: non-scaling-stroke;
}
var xmlns = "http://www.w3.org/2000/svg",
  xlinkns = "http://www.w3.org/1999/xlink",
  select = function(s) {
    return document.querySelector(s);
  },
  selectAll = function(s) {
    return document.querySelectorAll(s);
  },
  container = select('.container'),
  pContainer = select('.pContainer'),
    heartPool = 600,
    heartPoolArray = [],
    numHearts = 22,
    heartCount = 0,
    step = 360/numHearts,
    isDevice = (/android|webos|iphone|ipad|ipod|blackberry/i.test(navigator.userAgent.toLowerCase())),
    destParticle,
    strokeColors = ['#E187D2', '#E0A3FF', '#F5BB30', '#9ECA98', '#35A0F0', '#BADAB0', '#33B6E9']


//center the container cos it's pretty an' that
TweenMax.set(container, {
  position: 'absolute',
  top: '50%',
  left: '50%',
  xPercent: -50,
  yPercent: -60
})
TweenMax.set('svg', {
  visibility:'visible'
})

function createHeartPool() {
//console.log('createHeartPool');
  
  var i = heartPool, p;
  while (--i > -1) {

    p = document.createElementNS(xmlns, 'use');
    pContainer.appendChild(p);
    
    //console.log(i % 2)
     destParticle = (i % 2) ? '#heart' : '#dot';
    p.setAttributeNS(xlinkns, "xlink:href", destParticle);
    p.setAttributeNS(null, 'fill', "#ef2341")
    p.setAttributeNS(null, 'stroke', strokeColors[randomBetween(0, 6)])
    
    TweenMax.set(destParticle, {
      scale:(i % 2) ? 1 : 0.5
    })
    //heartArr.push(p);
    resetParticle(p);

  heartPoolArray.push(p);
  }
  //tl.play()

}

function createExplosion(x,y){

  var max = heartCount + numHearts, p;
  
  for(var i = heartCount; i < max; i++){
    p = heartPoolArray[i], localCount = i % numHearts;
    var radians = (step * localCount) * (Math.PI/180);
    var deg = radians * (180/Math.PI);
    //var px = Math.atan2(e.offsetY - 300, e.offsetX - 300)
   //console.log(radians,deg)
    TweenMax.set(p, {
      x:x,
      y:y,
      rotation:deg -90
    })    
    //console.log(i)
     var tl = new TimelineMax({paused:false});
  tl.to(p, 2, {
    //cycle:{
      physics2D: {
        gravity:0,
        //velocity:randomBetween(60, 200),
        velocity:400,
        angle:deg
        //angle:randomBetween(0, 360)
      },
    //rotation:randomBetween(0, 360),
    //fill:"hsl(="+ 360/(step * (localCount+1)) +", +=0%, +=100%)",
    alpha:0,
    ease:Expo.easeInOut,
    scale:0,
    onComplete:resetParticle,
    onCompleteParams:[p]
  }) 
  
  heartCount++;
}
  
  //if(heartCount)
  //console.log('heartCount: ' + heartCount);
  if(heartCount + numHearts >=heartPool){
    heartCount = 0;
  }
  
    var h = document.createElementNS(xmlns, 'use');
    var d = document.createElementNS(xmlns, 'use');
    pContainer.appendChild(h);
    pContainer.appendChild(d);

    h.setAttributeNS(xlinkns, "xlink:href", '#heart');
    h.setAttributeNS(null, 'fill', "#FFF"),
    d.setAttributeNS(xlinkns, "xlink:href", '#ring');
    d.setAttributeNS(null, 'stroke', strokeColors[randomBetween(0, 6)]),
    d.setAttributeNS(null, 'stroke-width', 2),
    
    
    TweenMax.set([h,d], {
      scale:1,
      transformOrigin:'50% 50%',
      x:x,
      y:y,
      fill:'#fff'
    })
    //heartArr.push(p);
    TweenMax.to(h, 2, {
    
      alpha:0,
      fill:'#ef2341',
      scale:20,
      //ease:Back.easeIn.config(5),
      ease:Circ.easeInOut,
      onComplete:function(){
        pContainer.removeChild(h)
      }
    })    
    TweenMax.to(d, 2, {
    
      alpha:0,
      fill:'#000',
      scale:10,
      strokeWidth:3,
      //ease:Back.easeIn.config(5),
      ease:Expo.easeOut,
      onComplete:function(){
        pContainer.removeChild(d)
      }
    })
  
}

function clearAll(){
  
  pContainer.innerHTML = ""
}

function resetParticle(p){
  
    TweenMax.set(p, {
      scale:2,
      transformOrigin:'50% 50%',
      x:-100,
      y:-100,
      alpha:1,
      fill:'#ef2341'
    })
}
//createHeartPool(-100, -100);



function randomBetween(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}

container.onclick =  function(e){
  var x = (isDevice) ? e.touches[0].pageX : e.offsetX;
  var y = (isDevice) ? e.touches[0].pageY+48 : e.offsetY;
  createExplosion(x, y)
  //console.log(x, y)
  
}

container.addEventListener('touchstart', container.onclick);
createHeartPool();
/* TweenMax.staggerTo([{l:0},{l:0},{l:0}], 0.1, {
  onComplete:function(){
    createExplosion(400,400)
  }
},0.1) */
function autoExplosion(){
    
  createExplosion(window.innerWidth/2, window.innerHeight/2)
  TweenMax.delayedCall(0.166, autoExplosion)

}

autoExplosion()
TweenMax.globalTimeScale(0.5)


External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js
  2. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/Physics2DPlugin.min.js