Recreating the Google Logo Animation with SVG and GreenSock

Avatar of Petr Tichy
Petr Tichy on (Updated on )

The following is a guest post by Petr Tichy. Petr writes a lot about animation, interaction, and SVG, so I’m excited to have him here to share some of that expertise with such a fun demo. It’s an animation I bet a lot of you have seen before, but feels kinda magical perhaps outside of what it feels like we can do on the web. Like was created by video artists / video editing software. But nope, SVG-can-do-that.

A little while ago, Google revealed their updated branding and introduced the new identity on a page with creative animations.

I tried to recreate some of these animations using SVG and GreenSock. In this article, I’ll walk you through my process step by step. Hopefully you can learn something along the way.

Here’s the final animation:

See the Pen Google SVG Logo – GreenSock Animation by Petr TIchy (@ihatetomatoes) on CodePen.

Setup SVG in Illustrator

The first step was to create an SVG with all the necessary parts that will be animated. I traced over a `.png` screenshot in Illustrator and created a simple outline of the circle.

To help me align things correctly, I divided this circle into 4 even parts. Then, I created 4 circles sitting on top of each other and 4 dots, trying to be as precise as I could.

I knew I would be using GreenSock for the animating, and I knew that the circles should be easy to animate using the DrawSVGPlugin.

To create the gap between the straight line of the “G” and the top part of the circle, I created an invisible white element #gMask (#1 and #2 on the illustration below). Quite ugly to be honest, but it did the job of creating the final “G” shape.

The straight line animation is created using 3 parts (#3 and #4 on the illustration below).

  • A – straight line with rounded edge – used at the start of the line animation
  • B – clipPath mask – cropping area
  • C – straight line – displayed at the end of the animation

While still in Illustrator, I grouped and named all the layers to something logical. This saved me time later in the code editor. Grouping and renaming elements of an SVG can be quite a slow process in HTML. It’s much easier to do it straight in Illustrator.

Then, I exported the SVG and ran it through Peter Collingridge’s SVG Online Editor to shave off some kilobytes.

The whole animation sequence can be broken down into 3 parts:

  1. Wave animation of the dots
  2. Dots into the letter “G”
  3. From “G” back to the dots

Lets break the individual parts down in more detail.

1. Wave animation of the dots

This is the first part of the animation, and it was the easiest to create.

See the Pen Google SVG Logo – GreenSock Animation by Petr TIchy (@ihatetomatoes) on CodePen.

We are simply animating the dots up and down using the GreenSock .to() method.

Each dot has its own timeline, dotWaveTl that moves it to y: -7, y: 7 and then back to y: 0.

All four timelines are then inserted onto a main timeline, dotsWaveTl, with a slight delay.

This creates the wave effects of all four dots.

function getDotsWaveTl(){
  var dotsWaveTl = new TimelineMax();

  $dots.each(function(index, element){

    var dotWaveTl = new TimelineMax(),
        delay = 0.15;

    dotWaveTl
      .to(element, 0.4, {y: -7, ease:Power1.easeOut})
      .to(element, 0.8, {y: 7, ease:Power1.easeInOut})
      .to(element, 0.4, {y: 0, ease:Power1.easeIn})
      .to(element, 0.4, {y: -7, ease:Power1.easeOut})
      .to(element, 0.8, {y: 7, ease:Power1.easeInOut})
      .to(element, 0.4, {y: 0, ease:Power1.easeIn});

    dotsWaveTl.add(dotWaveTl, delay*index);

  });

  return dotsWaveTl;
}

In this getDotsWaveTl function we loop through all the dots, creating a timeline for each of them, then insert these timelines on a dotsWaveTl that is returned by this function.

The individual tweens have different easing to make this wave feel more natural.

Then we simply add this timeline to the master timeline tl.

/* Main timeline */
tl.add(getDotsWaveTl());

We will be adding the other parts of the animation sequence to the same master timeline.

If you want to learn more about how GreenSock timelines work, check out my GreenSock TimelineLite Tutorial.

2. Dots into the letter “G”

This was by far the hardest part of the animation.

See the Pen Google SVG Logo – GreenSock Animation by Petr TIchy (@ihatetomatoes) on CodePen.

What made it so hard? A few things. I had to:

  • work out a path for each of the dots
  • work out a precise timing for each of the dots
  • work out the timing and animation for the straight blue line
  • synchronize dots and line animation

When we look at the code, you’ll see that this part of the animation is created using two timelines.

/* Dots rotation */
function getDotsRotateTl(){
  var dotsRotateTl = new TimelineMax();

  dotsRotateTl
    .to($dotRed, 0.9, {bezier:{curviness: 1.5, values: pathRed, ease:Power2.easeInOut}}, 0)
    .to($dotYellow, 1.2, {bezier:{curviness: 1, values: pathYellow, ease:Power2.easeInOut}}, 0)
    .to($dotGreen, 1.5, {bezier:{curviness: 1, values: pathGreen, ease:Power2.easeInOut}}, 0);

  return dotsRotateTl;
}

dotsRotateTl is a timeline where I am animating red, yellow, and green dots along a bezier path. I knew what the starting point was and where I wanted the dots to finish, and I just needed to work out the points in between.

pathRed is an array of points that are defining the path for the red dot animation.

The same technique is used for the yellow and green dots. I have defined 4 points for each and worked out the right duration (1.2s for yellow and 1.5s for green dot).

The second timeline is little bit more complex.

/* Draw G */
function getDrawGTl(){
  var drawGTl = new TimelineMax();

  drawGTl
    .to($dotBlue, 0.6, {x: 47, ease:Power2.easeIn})
    .set($gLineAnim, {autoAlpha: 1, immediateRender: false})
    .set($dotBlue, {autoAlpha: 0, immediateRender: false}, '+=0.1')
    .from($gLineAnim, 0.8, {x: -120, ease:Power2.easeOut}, '-=0.2')

    /* draw red part */
    .add('startDrawingG', 1)
    .set($gRed, {autoAlpha: 1, immediateRender: false}, 'startDrawingG')
    .fromTo($gRed, 0.5, {drawSVG:"71% 88%"}, {drawSVG:"0% 26%", ease:Power1.easeOut}, '-=0.2')
    .set($dotRed, {autoAlpha: 0, immediateRender: false}, 'startDrawingG')

    /* draw yellow part */
    .set($gYellow, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.1')
    .fromTo($gYellow, 0.6, {drawSVG:"71% 88%"}, {drawSVG:"17% 36%", ease:Power2.easeOut}, '-=0.45')
    .set($dotYellow, {autoAlpha: 0, immediateRender: false}, 'startDrawingG+=0.1')

    /* draw green part */
    .set($gGreen, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.1')
    .fromTo($gGreen, 0.55, {drawSVG:"71% 88%"}, {drawSVG:"36% 61%", ease:Power2.easeOut}, '-=0.6')
    .set($dotGreen, {autoAlpha: 0, immediateRender: false}, 'startDrawingG+=0.4')

    /* draw blue part */
    .set($gLineAnim, {autoAlpha: 0, immediateRender: false}, 'startDrawingG+=0.3')
    .set($gLine, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.3')
    .set($gBlue, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.3')
    .fromTo($gBlue, 0.55, {drawSVG:"71% 88%"}, {drawSVG:"61% 78%", ease:Power2.easeOut}, '-=0.55')

    /* draw ending red part */
    .set($gRedb, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.25')
    .fromTo($gRedb, 0.7, {rotation: '-10', drawSVG:"100% 100%"}, {rotation: '0',drawSVG:"80% 100%", ease:Power2.easeOut}, '-=0.22');

  return drawGTl;
}

The drawGTl timeline controls the movement of the blue dot. When it moves 47 pixels to the right, we hide it and show the line with rounded right edge (A) as shown on the second image of the SVG breakdown.

One second into the drawGTl timeline playback, I add the startDrawingG label. This lets me add other tweens at the right time and precisely control them by adjusting their offset e.g. startDrawingG+=0.3.

Once the red dot reaches the intersection point, we hide it and show the red circle, which is then animated using GreenSock DrawSVGPlugin.

.fromTo($gRed, 0.5, {drawSVG:"71% 88%"}, {drawSVG:"0% 26%", ease:Power1.easeOut}, '-=0.2')

At this moment, and throughout the whole development of this demo, I have heavily used the jQuery UI slider to precisely work out the right values and timings.

Once the red segment is drawn long enough, we are doing the same with the all the following segments.

The starting point is the same for all 71% 88% segments, but the ending point is different for each of them.

To complete the drawing of the whole letter “G” using the DrawSVGPlugin, I had to duplicate the red circle and animate the new $gRedb at the right time.

I made this update straight in the HTML; no going back to Illustrator.

.fromTo($gRedb, 0.7, {rotation: '-10', drawSVG:"100% 100%"}, {rotation: '0', drawSVG:"80% 100%", ease:Power2.easeOut}, '-=0.22');

A combination of rotation, drawSVG values, timing, and the right offset enabled me to create the seamless animation of the red segment.

3. From “G” back to the dots

The animation back to the dots was much easier to create. I used the same techniques as in the previous timeline, just in a reversed order.

See the Pen Google SVG Logo – GreenSock Animation by Petr TIchy (@ihatetomatoes) on CodePen.

I first used the DrawSVGPlugin to make the colored segments shorter, then stared to rotate them.

When the colored segment is small enough I hide it, show the relevant dot and animate it to the starting position.

Here is an illustration of what is happening on the timeline:

And here is the whole function returning this timeline:

/* Back to dots */
function getBackToDotsTl(){
  var backToDotsTl = new TimelineMax();

  backToDotsTl
    /* blue straight line out */
    .to($gLineMask, 0.3, {attr: {x: 365}, transformOrigin: 'right center', ease:Power0.easeNone})
    .set([$gLineMask, $gLine], {autoAlpha: 0})

    /* start moving colored segments (circles) */
    .add('rotateG')
    .to($gBlue, 0.3, {drawSVG:"56% 78%", ease:Power0.easeNone}, 'rotateG-=0.3')
    .to($gGreen, 0.3, {drawSVG:"31% 56%", ease:Power0.easeNone}, 'rotateG-=0.3')
    .to($gYellow, 0.3, {drawSVG:"12% 31%", ease:Power0.easeNone}, 'rotateG-=0.3')
    .to($gRed, 0.3, {drawSVG:"0% 21%", ease:Power0.easeNone}, 'rotateG-=0.3')

    /* start rotating colored segments (circles) */
    .add('rotateCircles')
    .to([$gBlue, $gRed, $gGreen], 0.4, {rotation:"+=50", transformOrigin: 'center center', ease:Power0.easeNone}, 'rotateCircles')

    .to($gGreen, 0.4, {drawSVG:"10% 20%", ease:Power0.easeNone}, 'rotateCircles')
    .to($gYellow, 0.4, {rotation:"+=40", transformOrigin: 'center center', drawSVG:"0% 10%", ease:Power0.easeNone}, 'rotateCircles')
    .to($gBlue, 0.4, {drawSVG:"50% 60%", ease:Power0.easeNone}, 'rotateCircles')
    .to($gRed, 0.1, {drawSVG:"0% 0%", ease:Power0.easeNone}, 'rotateCircles')
    .to($gRedb, 0.3, {rotation:"+=50", drawSVG:"80% 90%", ease:Power2.easeInOut}, 'rotateCircles')

    /* show red dot */
    .set($dotRed, {autoAlpha: 1, x: 60, y: -37}, 'rotateCircles+=0.1')
    .set($gRedb, {autoAlpha: 0}, 'rotateCircles+=0.1')
    .to($dotRed, 0.9, {bezier:{curviness: 1.5, values: pathRedBack, ease:Power2.easeOut}}, 'rotateCircles+=0.1')

    /* show blue dot */
    .set($dotBlue, {autoAlpha: 1, x: 51, y: 53}, 'rotateCircles+=0.3')
    .set($gBlue, {autoAlpha: 0}, 'rotateCircles+=0.3')
    .to($dotBlue, 0.6, {bezier:{curviness: 1.5, values: pathBlueBack, ease:Power2.easeOut}}, 'rotateCircles+=0.3')

    /* show yellow dot */
    .set($dotYellow, {autoAlpha: 1, x: -5, y: -44}, 'rotateCircles+=0.4')
    .set($gYellow, {autoAlpha: 0}, 'rotateCircles+=0.4')
    .to($dotYellow, 0.7, {bezier:{curviness: 1.5, values: pathYellowBack, ease:Power2.easeOut}}, 'rotateCircles+=0.4')

    /* show green dot */
    .set($dotGreen, {autoAlpha: 1, x: -108, y: -56}, 'rotateCircles+=0.4')
    .set($gGreen, {autoAlpha: 0}, 'rotateCircles+=0.4')
    .to($dotGreen, 0.6, {bezier:{curviness: 1.5, values: pathGreenBack, ease:Power2.easeOut}}, 'rotateCircles+=0.4')

    .to($gMask, 0.3, {rotation:"+=60", transformOrigin: '-9 58', ease:Power2.easeInOut}, 'rotateCircles');

  return backToDotsTl;
}

I have used the rotateG and rotateCircles labels to position most of the tweens on this timeline exactly where I wanted.

Then, I have included this function on the main timeline and adjusted the exact time where to insert it.

/* Main timeline */
tl.add(getDotsWaveTl())
  .add(getDotsRotateTl(), '-=0.35')
  .add(getDrawGTl(), '-=1.6')
  .add(getBackToDotsTl(), '+=2');

tl.timeScale(1.8);

getBackToDotsTl is inserted with a 2 seconds delay, ('+=2'), which makes the “G” stay fully completed for 2 seconds before animating back to the dots.

I also tweaked the final speed of the animation by setting the timeScale to 1.8 instead of the default 1. Feel free to change the value to see the animation at a different speed.

The last function to mention is init().

/* Init */
function init(){
  TweenLite.set([$gLine,$circles], {autoAlpha: 0});
  TweenLite.set($gBlue, {drawSVG:"61% 78%"}); /* start at 71% 78% */
  TweenLite.set($gGreen, {drawSVG:"36% 61%"});
  TweenLite.set($gYellow, {drawSVG:"17% 36%"});
  TweenLite.set($gRed, {drawSVG:"0% 26%"});
  TweenLite.set($gRedb, {drawSVG:"78% 100%", transformOrigin: 'center center'});
  TweenLite.set($gLineAnim, {autoAlpha: 0});
}
init();

This is a function where I am setting everything up e.g. hiding a few elements, making segments the right length, etc.

I use this function on a more complex GSAP animations such as this SVG GreenSock Lab to get the right starting point I need, because most of the time I am exporting the final design or frame that contains all the assets from Illustrator.

In other words, this function sets up the right canvas for the beginning.

Why did I use GreenSock?

There are already a few articles about GreenSock on CSS-Tricks, so I assume you may already know its strengths. But, here are a few reasons why I picked this animation library for the job:

  • GSAP give you a precise control over timing and duration of individual tweens and timelines
  • GSAP API offers incredibly flexible nesting of timelines
  • GSAP fixes a lot of cross-browser inconsistencies when working with SVGs
  • jQuery UI slider lets you scrub through GSAP timeline and speed up development
  • GSAP lets you concentrate on the creative part of your interactive projects
  • using labels is great for a more complex timelines

Conclusion

I know some of the code snippets and timelines from my animation might look overwhelming, so feel free to ask any questions in the comments bellow or hit me up on Twitter @ihatetomatoes.