<div id="featureBox"></div>
<div style="position:relative; width:936px; height:0px; overflow:visible; z-index:20;" id="violator"><img src="https://gsap.com/_img/legacy/HTML5_corner_banner.png" alt="HTML5" style="position:absolute; top:-5px; right:-5px;" /></div>
<div class="feature" id="featureAnimation">
  <div id="featureBackground" style="pointer-events:none;"></div>
  <div class="featureTextWhite" id="whyGSAP">Why GSAP?</div>
  <div class="featureTextGreen" id="performance">Performance</div>
  <div class="featureTextWhite" id="compatibility">Compatibility</div>
  <div id="browserIcons">
    <img src="https://gsap.com/_img/legacy/browser-chrome-big.png" width="82" height="80" />
    <img src="https://gsap.com/_img/legacy/browser-safari-big.png" width="77" height="86"  />
    <img src="https://gsap.com/_img/legacy/browser-ie-big.png" width="82" height="74" />
    <img src="https://gsap.com/_img/legacy/browser-firefox-big.png" width="82" height="83" />
    <img src="https://gsap.com/_img/legacy/browser-opera-big.png" width="69" height="75" />
  </div>
  <div class="featureTextMinor" id="fallDown">Other tools fall down in older browsers, but GSAP is remarkably compatible.</div>
  <img id="anythingIcon" src="https://gsap.com/_img/legacy/animate-anything.png" width="102" height="108" style="position:absolute; top:50px; left:143px; display:block;" />
  <div id="transformBox" style="background-color:#91e600; width:130px; height:130px; position:absolute; top:40px; left:100px;"></div>
  <div class="featureTextWhite" id="transform" style="font-size:34px; width:640px; text-align:left; left:270px; top:80px; line-height:36px;">Scale, rotate & move independently</div>
  <div class="featureTextWhite" id="transformSub" style="font-size:16px; width:420px; text-align:left; left:270px; top:122px; color:#CCCCCC;">(impossible with CSS animations/transitions)</div>
  <div class="featureTextWhite" id="anything" style="width:620px; text-align:left; left:302px; top:63px;">XNJYHQLJYQEW</div>
  <div class="featureTextWhite" id="anythingSub" style="font-size:16px; width:390px; text-align:left; left:300px; top:122px; color:#CCCCCC;">CSS, SVG, canvas libraries, colors, beziers, etc.</div>
  <div class="featureTextWhite" id="control" style="text-align: left; top:64px; left:130px;">Total control</div>
  <div class="featureTextWhite" id="controlSub" style="font-size:16px; text-align:left; left:130px; top:122px; color:#CCCCCC;">pause(), play(), reverse(), or timeScale() any tween or sequence.</div>
  
  <div class="featureTextWhite" id="GSAP" style="top:60px;">GSAP</div>
  <div class="featureTextMinor" id="newStandardText" style="top:125px; text-align: center; width: 936px;">The new standard for HTML5 animation</div>
  <div id="featureClick" style="position:absolute; width:936px; height:220px;"><img src="https://gsap.com/_img/legacy/blank.gif" width="936" height="220" /></div>
  <div id="replay" style="text-align:right; position:absolute; left:825px; top:190px; cursor:pointer; color:#999999; font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; font-size:12px; width:100px; visibility:hidden;">replay <img id="replayIcon" src="https://gsap.com/_img/legacy/replay.png" width="19" height="19" style="margin-left:2px; vertical-align: middle;" /></div>
  <div id="ctrl_slider"></div>
</div>
body {
  background-color:#333;
  overflow: hidden;
}
#featureAnimation, #featureBox {
  background-color:#000;
  height: 220px;
  overflow:hidden;
  line-height: normal;
  font-size: 80%;
}
#featureAnimation {
  position:relative;
  visibility:hidden;
  margin: 0 auto;
}
#featureBox {
  position:absolute;
}
#featureAnmation, #featureBox, #violator {
  left: 50%;
  transform: translate(-50%, 0);
}
#featureAnimation, #featureBox, #whyGSAP, .featureTextGreen, .featureTextWhite {
  width: 936px;
}
#whyGSAP, .featureTextGreen, .featureTextWhite {
  text-align: center;
}
#whyGSAP, .featureTextGreen, .featureTextWhite {
  font-size:50px;
  position:absolute;
  font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;
  top:0;
}
.featureTextGreen {
  color:#91e600;
  font-weight: bold;
}
.featureTextWhite {
  color:white;
  font-weight:normal;
}
.star {
  position: absolute;
  width: 16px;
  height: 16px;
  display: none;
}
#browserIcons {
  top:64px;
  left: 180px;
  width: 92px;
  height: 92px;
  position: absolute;
  text-align:left;
}
#browserIcons img {
  position:absolute;
}
.featureTextMinor {
  color:#CCCCCC;
  font-weight:normal;
  font-size:20px;
  position:absolute;
  font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;
  visibility:hidden;
}
.dot {
  position:absolute;
  background-color: #91e600;
}
#ctrl_slider {
  position:absolute;
  width: 824px;
  height:10px;
  left:18px;
  top:196px;
  background: rgba(80,80,80,0.3);
  border:1px solid rgba(102,102,102,0.5);
  visibility:hidden;
}
/*
* See https://greensock.com/ for details about GSAP.
* 
* We simply create a timeline and then each part of the 
* animation is modularized into its own function that returns a 
* tween or timeline, which we dump into the main timeline to very
* easily build something much more complex. It also allows us to
* jump around during production to various spots using times or labels
* like when we're tweaking the part that's 30 seconds into the animation, 
* we just add master.seek(30) at the end to have it jump there for preview
* (rather than watching the first 30 seconds every...single...time). 
* This technique also allows us to attach a scrubber to the entire
* thing, speed it up or slow it down, re-order the pieces of the animation, etc. 
*/
gsap.registerPlugin(MotionPathPlugin, SplitText, Physics2DPlugin, ScrambleTextPlugin, EasePack)

var master = gsap.timeline({delay:1.2}),
    bg = $("#featureBackground"),
    centerY = $("#featureAnimation").height() / 2,
    centerX = $("#featureAnimation").width() / 2,
    radius = Math.max(centerX, centerY) + 50,
    slider = $("#ctrl_slider"),
    sliderValue = {value:0},
    _isOldIE = (document.all && !document.addEventListener);

gsap.set("#featureBox, #violator", {left:"50%", x:0, xPercent:-50}); //center things

slider.slider({
  range: false,
  min: 0,
  max: 100,
  step:.1,
  start:function() {
    master.pause();
  },
  slide: function ( event, ui ) {
    master.progress( ui.value / 100 );
  },
  stop:function() {
    master.play();
  }
});

master.eventCallback("onUpdate", function() {
  sliderValue.value = master.progress() * 100;
  slider.slider(sliderValue);
});
master.eventCallback("onComplete", function() {
  gsap.to(slider, 1, {autoAlpha:1});
  replayReveal();
});
$("#featureClick").on("click", function() {
  window.location.href = "https://greensock.com/gsap/";
});

gsap.set(".featureTextGreen", {textShadow:"0px 0px 8px #91e600"});

//build master timeline with nested scenes...
master.add( whyGSAP() )
      .add( performance(), "-=1")
      .add( compatibility(), "-=0.5")
      .add( transforms(), "-=3.6")
      .add( animateAnything(), "-=0.5")
      .add( control(), "-=0.5")
      .add( newStandard());

//master.seek(42); //during production, jump to the spot you're working on.

function whyGSAP() {
  var tl = gsap.timeline(),
      text = $("#whyGSAP"),
      split = new SplitText("#whyGSAP", {type:"chars,words"}),
      chars = split.chars,
      centerIndex = Math.floor(chars.length / 2),
      i;
  for (i = 0; i < chars.length; i++) {
    tl.from(chars[i], {x:(i - centerIndex) * 40, opacity:0, duration: 1.8, ease: "power2"}, i * 0.1);
  }
  tl.fromTo(text, {z:500, y:74, visibility:"visible"}, {z:-1000, ease:"slow(0.1, 0.9)", duration: 4}, 0);
  tl.to(text, {rotationX:-720, autoAlpha:0, scale:0.3, duration: 1.5, ease:"power2.inOut"}, "-=1.5");
  return tl;
}

function performance() {
  var tl = gsap.timeline(),
      text = $("#performance"),
      duration = 0.6,
      i = 45,
      repeats = 2,
      stars = [],
      star, angle, delay;
  while (--i > -1) {
    star = $("<img class='star' src='//www.greensock.com/js/img/dot.png'/>").appendTo(bg);
    stars.push(star);
    angle = Math.random() * Math.PI * 2;
    delay = Math.random() * duration;
    tl.set(star, {display:"block"}, delay);
    if (_isOldIE) {
      //IE8 and earlier perform better when animating top/left/width/height instead of x/y/scale.
      gsap.set(star, {width:1, height:1, top:centerY, left:centerX});
      tl.to(star, {
        duration: duration,
        top:(centerY + Math.sin(angle) * radius) | 0,
        left:(centerX + Math.cos(angle) * radius) | 0,
        width:22,
        height:22,
        ease:"cubic.in",
        repeat:repeats,
        repeatDelay:Math.random() * duration},
             delay);
    } else {
      gsap.set(star, {scale:0.05, top:centerY, left:centerX, z:0.1});
      tl.to(star, duration, {
        duration: duration,
        y:Math.sin(angle) * radius,
        x:Math.cos(angle) * radius,
        scale:1.5,
        ease:"cubic.in",
        repeat:repeats,
        repeatDelay:Math.random() * duration},
             delay);
    }
  }
  tl.fromTo(text, {scale:0.1, y:centerY-36, z:0.1}, {scale:1.8, duration: 3, ease: "slow(0.5, 0.4)"}, 0.3);
  tl.fromTo(text, {opacity:0}, {autoAlpha:1, duration: 3, ease:"slow(0.5, 0.4, true)"}, 0.3);
  tl.set(stars, {display:"none"});
  return tl;
}

function compatibility() {
  var tl = gsap.timeline(),
      iconTimeline = gsap.timeline({repeat:1}),
      icons = $("#browserIcons img"),
      text = $("#compatibility"),
      split = new SplitText(text, {split:"chars", absolute:true}),
      rough = RoughEase.ease.config({strength:2, clamp:true}),
      i;
  for (i = 0; i < icons.length; i++) {
    iconTimeline.fromTo(icons[i], {scaleX:0, opacity:0.4, z:0.1}, {autoAlpha:1, scaleX:1, duration: 0.6, ease:"power2"});
    iconTimeline.to(icons[i], {scaleX:0, opacity:0.4, duration: 0.6, ease:"power2.in"});
    iconTimeline.set(icons[i], {visibility:"hidden"});
  }
  tl.add(iconTimeline, 0);
  tl.fromTo("#browserIcons", {transformOrigin:"center -160px", rotation:170, z:0.1}, {rotation:0, duration: 2.8, ease:"elastic"}, 0);
  tl.set(text, {y: centerY-35, x:10, autoAlpha:1}, 0);
  for (i = 0; i < split.chars.length; i++) {
    tl.fromTo(split.chars[i], {transformOrigin:"center -160px", z:0.1, rotation:((Math.random() < 0.5) ? 90 : -90)}, {rotation:0, duration: 2.4, ease:"elastic"}, 0.3 + i * 0.06);
    
    tl.to(split.chars[i], {y:97, ease:"bounce", duration: 0.6}, 3.4 + Math.random() * 0.6);
    tl.to(split.chars[i], {autoAlpha:0, ease:rough, duration: 0.6}, 4.5 + Math.random());
  }
  gsap.set("#fallDown", {width:420, left:300, top:-35, autoAlpha:0, textAlign:"left"});
  tl.to("#fallDown", {top:81, autoAlpha:1, ease:"back", duration: 0.5}, 3.9);
  tl.to("#browserIcons", {autoAlpha:0, duration: 0.5}, 8);
  tl.to("#fallDown", {left:"-=100", autoAlpha:0, duration: 0.5, ease:"power1.in"}, 8);
  return tl;
}

function transforms() {
  var tl = gsap.timeline(),
      split = new SplitText("#transform", {split:"words", absolute:true}),
      box = document.getElementById("transformBox"),
      transformSub = document.getElementById("transformSub"),
      scale = split.words[0],
      rotate = split.words[1],
      move = [split.words[2], split.words[3]],
      independently = split.words[4];
  gsap.set(split.words, {autoAlpha:0, rotationX:-90});
  gsap.set(box, {scale:0.1, rotation:0.1, autoAlpha:0});
  tl.to(box, 0.3, {autoAlpha:1});
  tl.to(box, 7, {scale:1, ease:Linear.easeNone, autoRound:false}, 0);
  tl.to(scale, 0.5, {autoAlpha:1, rotationX:0, transformOrigin:"50% 50% -35px"}, 0);
  tl.to(box, 6, {rotation:360.2}, 1);
  tl.to(rotate, 0.5, {autoAlpha:1, rotationX:0, transformOrigin:"50% 50% -35px"}, 1);
  tl.to(box, 0.3, {x:60, ease:Power1.easeInOut}, 2.2);
  tl.to(box, 1.8, {x:0, ease:Elastic.easeOut}, 2.5);
  tl.to(move, 0.5, {autoAlpha:1, rotationX:0, transformOrigin:"50% 50% -35px"}, 2);
  tl.to(independently, 0.5, {autoAlpha:1, rotationX:0, transformOrigin:"50% 50% -35px"}, 2.5);
  tl.to(box, 3, {rotationX:360, ease:"elastic"}, 3.5);
  tl.from(transformSub, 0.5, {top:"-=16", autoAlpha:0}, 4.5);
  tl.to([transformSub, box], 0.5, {autoAlpha:0}, 7.4);
  tl.staggerTo(split.words.slice(0, 4), 0.5, {rotationX:90, autoAlpha:0}, 0.2, 7);
  tl.to(independently, 0.5, {rotationX:-90, autoAlpha:0}, 7.3);
  return tl;
}

function animateAnything() {
  var tl = gsap.timeline(),
      anything = document.getElementById("anything"),
      icon = document.getElementById("anythingIcon"),
      sub = document.getElementById("anythingSub");
  gsap.set([anything,icon], {autoAlpha:0});
  tl.to([anything, icon], 0.9, {autoAlpha:1});
  tl.to(anything, 2.5, {scrambleText:{text:"Animate anything", revealDelay:0.7}}, 0);
  tl.from(sub, 0.5, {top:"-=20", autoAlpha:0}, 2.5);
  tl.staggerTo([anything, sub, icon], 0.6, {left:"-=150", autoAlpha:0, ease:"power1.in"}, 0.1, 6);
  return tl;
}

function control() {
  var dots = gsap.timeline({paused:true}),
      tl = gsap.timeline(),
      qty = 30,
      duration = 2.5,
      xProp = _isOldIE ? "left" : "x",
      yProp = _isOldIE ? "top" : "y",
      colors = ["#91e600","#84d100","#73b403","#528003"],
      startVars = {css:{}},
      initialVars = {css:{borderRadius:"50%", width:100, z:0.1}, immediateRender:true},
      split = new SplitText("#controlSub", {split:"words", absolute:"true"}),
      pause = split.words[0],
      play = split.words[1],
      reverse = split.words[2],
      timeScale = [split.words[3], split.words[4]],
      subEnd = [split.words[5], split.words[6], split.words[7], split.words[8]],
      dot, i, delay;
  startVars.css[xProp] = initialVars.css[xProp] = 680;
  startVars.css[yProp] = initialVars.css[yProp] = 220;
  for (i = 0; i < qty; i++) {
    dot = $("<div class='dot'/>").appendTo(bg)[0];
    initialVars.css.width = initialVars.css.height = ((Math.random() * 15 + 10) | 0);
    initialVars.css.backgroundColor = colors[(Math.random() * colors.length) | 0];
    gsap.set(dot, initialVars);
    delay = Math.random() * duration;
    dots.to(dot, duration, {physics2D:{velocity:Math.random() * 300 + 150, angle:Math.random() * 40 + 250, gravity:400, xProp:xProp, yProp:yProp}}, delay);
    dots.fromTo(dot, duration, startVars, {physics2D:{velocity:Math.random() * 300 + 150, angle:Math.random() * 60 + 240, gravity:400, xProp:xProp, yProp:yProp}, immediateRender:false, overwrite:"none"}, delay + duration);
    dots.fromTo(dot, duration, startVars, {physics2D:{velocity:Math.random() * 300 + 150, angle:Math.random() * 60 + 240, gravity:400, xProp:xProp, yProp:yProp}, immediateRender:false, overwrite:"none", display:"none"}, delay + duration * 2);
  }
  tl.to(dots, 2.2, {time:2.2, ease:"none"}, 0);
  tl.from("#control", 0.5, {left:"+=100", autoAlpha:0}, 0);
  tl.from(pause, 0.4, {autoAlpha:0, scale:2}, 2);
  tl.from(play, 0.4, {autoAlpha:0, scale:2}, 4);
  tl.to(dots, 2, {time:4.2, ease:"none"}, 4.2);
  tl.from(reverse, 0.4, {autoAlpha:0, scale:2}, 6);
  tl.to(dots, 2, {time:2.2, ease:"none"}, 6.2);
  tl.from(timeScale, 0.4, {autoAlpha:0, scale:2}, 8);
  tl.to(dots, 2, {time:3.2, ease:"none"}, 8.2);
  tl.from(subEnd, 0.4, {autoAlpha:0}, 10);
  tl.to(dots, 3, {time:dots.duration(), ease:"none"}, 10.2);
  tl.staggerTo(["#control", "#controlSub"], 0.8, {left:"-=100", autoAlpha:0, ease:Power1.easeIn}, 0.15, 12.6);
  return tl;
}

function newStandard() {
  var tl = gsap.timeline(),
      GSAP = document.getElementById("GSAP"),
      split = new SplitText(GSAP, {type:"chars", position:"absolute"}),
      chars = split.chars,
      positions = [chars[0].offsetLeft],
      i, xOffset;
  positions[5] = chars[1].offsetLeft;
  positions[9] = chars[2].offsetLeft;
  positions[18] = chars[3].offsetLeft;
  split.revert();
  GSAP.innerHTML = "GreenSock Animation Platform";
  split.split({type:"words,chars"});
  tl.staggerFrom(split.words, 1.5, {z:-1000, autoAlpha:0, ease:Power1.easeOut}, 0.3);
  tl.from("#newStandardText", 1, {autoAlpha:0});
  if (!_isOldIE) {
    chars = split.chars;
    for (i = 0; i < chars.length; i++) {
      gsap.set(chars[i], {force3D:true});
      if (positions[i]) {
        xOffset = positions[i] - (chars[i].offsetLeft + chars[i].parentNode.offsetLeft);
        tl.to(chars[i], 3, {motionPath:{path:[{x:20, y:0}, {x:40, y:0}, getRandomPosition(chars[i], true), {x:xOffset - 100, y:0}, {x:xOffset - 10, y:0}, {x:xOffset, y:0}], autoRotate:true}, ease:"power2.inOut", color:"#91e600"}, i * 0.05 + 5);
      } else {
        tl.to(chars[i], 3, {motionPath:{path:[{x:20, y:0}, {x:40, y:0}, getRandomPosition(chars[i], true), getRandomPosition(chars[i], false)], autoRotate:true}, ease:"power2.inOut"}, i * 0.05 + 5);
        tl.set(chars[i], {visibility:"hidden"}, 8 + i * 0.05);
      }
    }
  }
  return tl;
}

function getRandomPosition(element, inside) {
  var xStart = element.offsetLeft + element.parentNode.offsetLeft;
  return {x:Math.random() * 950 - xStart, y:(inside ? Math.random() * 160 - 80 : (Math.random() < 0.5) ? 200 : -200)};
}

function replayReveal() {
  var tl = gsap.timeline(),
      $replayIcon = $("#replayIcon"),
      $replay = $("#replay").mouseenter(function(){
        gsap.to($replayIcon, 0.4, {rotation:"+=360"});
        gsap.to($replay, 0.4, {opacity:1});
      }).mouseleave(function(){
        gsap.to($replay, 0.4, {opacity:0.65});
      }).click(function(){
        master.restart();
      });
  tl.from($replay, 0.5, {autoAlpha:0, scale:2});
  tl.from($replayIcon, 0.5, {rotation:"360_ccw"});
  return tl;
}
gsap.set("#featureAnimation", {perspective:700, visibility:"visible"});

External CSS

  1. //ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js
  2. //ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js
  3. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js
  4. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/ScrambleTextPlugin3.min.js
  5. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/Physics2DPlugin3.min.js
  6. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/SplitText3.min.js
  7. //greensock.com/js/src/3rd-party/jquery.ui.touch-punch.js
  8. https://cdn.jsdelivr.net/npm/gsap@3.8.0/dist/EasePack.min.js
  9. https://cdn.jsdelivr.net/npm/gsap@3.8.0/dist/MotionPathPlugin.min.js