In this tutorial you will learn how to create a playful Jump Loader animation using SVG and GSAP, the animation platform by GreenSock. The Jump Loader effect relies on a very useful plugin, the DrawSVGPlugin, which is a premium plugin that will help you with many SVG animations and effects.

FREE DrawSVGPlugin Exclusively for Codrops readers, until April 1, 2015 GreenSock has been kind enough to offer our readers a FREE “Simply Green” membership to Club GreenSock which gets you access to the DrawSVGPlugin used in the demos, plus several other bonus plugins. GSAP itself is free to download and available on GitHub, but there are a few non-essential (but very cool) plugins that GreenSock gives as “thank you” gifts to their supporters (Club GreenSock members). The offer expires on April 1, 2015, so sign up now using coupon code CODROPS to get your free “Simply Green” membership or a $50 discount off any other plan.

Note that the demo files will work locally on your machine but if you’d like to use one of the effects that requires the DrawSVGPlugin in production, you’ll need to have a GreenSock membership.

In the following, I’m going to show you how to create the Jump Loader, in detail. For that, I’ll be making use of GSAP’s sequencing tool TimelineMax and the DrawSVGPlugin. The DrawSVGPlugin is used for progressively revealing (or hiding) the stroke of an SVG which comes in really handy for the loader effects.

For some more background on GSAP and the other tools used I recommend the following resources:

Some of you might be familiar with these tools but for those of you who are not, GSAP is a set of JavaScript libraries that can animate almost any value.

So to business – we’re going to walk through the creation of the Jump Loader – it’s a fun animation that looks like a line is jumping out of some liquid and diving back in again. Because, well, why not.

Let’s start with breaking down the SVG inside the HTML:

<div id="container"> <svg id="loader" width="200px" height="200px" viewBox="0 0 200 200"> <path id="jump" fill="none" stroke="#2d2d2d" stroke-width="10" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M47.5,94.3c0-23.5,19.9-42.5,44.5-42.5s44.5,19,44.5,42.5" /> <g stroke="#2d2d2d" stroke-width="1"> <ellipse id="circleL" fill="none" stroke-miterlimit="10" cx="47.2" cy="95.6" rx="10.7" ry="2.7" /> <ellipse id="circleR" fill="none" stroke-miterlimit="10" cx="136.2" cy="95.6" rx="10.7" ry="2.7" /> </g> </svg> </div>

This SVG was created using Adobe Illustrator, although there are other tools out there like Sketch (Mac only) or Inkscape that can do the same. I drew the curved ‘jump’ line and the two ripple circles in Illustrator as shown below. You’ll notice there’s a big red box around the graphics and the reason is this: when you select and copy graphics from Illustrator into your HTML page, the viewBox dimensions for the SVG are taken from the entire bounding box of that selection. This means that if I was to just select the jump line and the circles, the SVG’s viewBox would only be the width and height of those selected graphics as a group, leaving no breathing space around the animation (don’t forget we’ll be animating the ripple circles outwards on the SVG canvas so we’ll need extra space for those to expand into).

To create the bigger SVG canvas (and to place the graphics in the center of the SVG) I copy a rectangle along with it – so if I want an SVG canvas of 200 x 150 (which this is) then I just make the rectangle 200 x 150, select all my graphics along with it (which together are smaller than 200 x 150) and copy them into the HTML. Then I simply delete the rectangle. It’s just a little trick I use to avoid animations or strokes cropping off the edge of the SVG canvas (or painstakingly having to adjust all the values of the SVG elements to move them inside the canvas).

So the elements we have are the ‘jump’ line and the two ‘ripple’ circles. Notice the jump line and circles have an ID assigned to them – you can create these IDs in Illustrator by renaming the layer of that graphic although it often comes out with extra characters added to the end which is a little frustrating. Some of the attributes that Illustrator adds to the SVG element can be removed, leaving only the viewBox and the dimensions.

So that’s the HTML with SVG.

The Structure and Layout

We start by referencing everything we’ll need. I always create variable references to document elements – this way you have a cached reference and the code doesn’t need to keep traversing the DOM every time you want to tell an element to do something. Be aware though that this can take up valuable memory on mobile devices, so this should be a consideration for your target device(s).

var container = document.getElementById('container'); var loader = document.getElementById('loader'); var circleL = document.getElementById('circleL'); var circleR = document.getElementById('circleR'); var jump = document.getElementById('jump');

You can see that the jump line has a reflection which we haven’t drawn so let’s clone it (make a copy) and add it ‘loader’, which is the reference for the entire SVG – we will flip it and change its opacity in a moment.

var jumpRef = jump.cloneNode(); loader.appendChild(jumpRef);

Next up: some simple centering using GSAP. We’ll center the container and the SVG inside using TweenMax because this only needs to be set once and doesn’t need to be part of the timeline animation. The xPercent and yPercent features are the CSS equivalent of transform: translate(-50%, -50%) but with all the vendor prefixes included.

TweenMax.set([container, loader], { position: 'absolute', top: '50%', left: '50%', xPercent: -50, yPercent: -50 })

And finally, for the layout we’ll use TweenMax to flip the jump reflection by changing its transform origin to 110% on the Y axis and using a negative scaleY value. We could use 100% (the bottom) for the transform origin but the reflection ends up being a bit too close underneath.

TweenMax.set(jumpRef, { transformOrigin: '50% 110%', scaleY: -1, alpha: 0.05 })

Let’s Animate!

We’re ready to build the animation using TimelineMax and taking advantage of its ability to chain animations. I’ll talk a bit more on chaining in a moment.

First off, we create a reference to a new instance of TimelineMax. The TimelineMax instance also takes an object where you can set all sorts of properties and event handlers like delay, yoyo , onComplete and more – here we’ll set it to repeat forever (using -1).

var myTimeline = new TimelineMax({ repeat: -1 });

Now we can start adding tweens to the timeline. As mentioned earlier TimelineLite/Max tweens can be chained together meaning you don’t need to keep declaring the instance variable every time you add a tween. You only need to do it once at the start (just make sure you don’t put any semi-colons between tweens).

First off let’s use GSAP’s DrawSVGPlugin to tell both the jump line and its reflection to be ‘undrawn’. The space delimited value defines a segment – here ‘0% 0%’ means that the start and end of the segment are both set to 0% and they are ready to start drawing from the left – there’s a useful video that goes into more depth. Note that we can animate both lines at the same time by passing them both into TimelineMax as an array.

We’ll also set the circle ripples to have an X and Y axis radius of 0 (i.e. tiny/invisible) using the ‘attr’ syntax which is built into TweenMax, designed to animate attributes. Note that there’s no semi-colon after the first set call – this allows the next calls to be chained to it without the need to declare the ‘myTimeline’ instance again.

myTimeline.set([jump, jumpRef], { drawSVG:'0% 0%' }) .set([circleL, circleR], { attr: { rx: 0, ry: 0, } })

Remember, these are still just setting the values – no actual animation has happened yet. The timeline will repeat forever so every time it plays from the start these will be called to initialize the elements’ states. So far the timeline’s duration is still 0.

These next calls are to calls which are actual animations – hooray!

Both lines begin to animate to 30% of their full length. The DrawSVG value of ‘0% 30%’ means that the segment start is still at 0% and the current length is 30% of its entire length – the image below shows where this happens in the animation. We also use a flat linear ease to achieve a progressive smooth ‘draw’ effect.

.to([jump, jumpRef], 0.4, { drawSVG: '0% 30%', ease: Linear.easeNone })

Next, we tell the left ripple circle to ‘scale’ up by animating its rx and ry attributes. If they were both animating to the same value like ‘+=30’ then the circle would be uniform – but that’s not how ripples in perspective look, so we make sure the rx value is greater than the ry value giving it that oval look. This is automatically added to the end of the timeline (which is currently 0.4 seconds because that’s the duration of the first animation).

However we’ve added in an extra ‘offset’ parameter at the end (‘-=0.1’). This means it will be added at 0.3 seconds (0.4 – 0.1). This helps to blend animations together a bit more otherwise it can seem too mechanical.

.to(circleL, 2, { attr:{rx:'+=30', ry:'+=10' }, alpha:0, ease:Power1.easeOut }, '-=0.1')

Let’s continue to animate the lines – now they’re moving forward and the tail is catching up. Again we’ve added it to the end of the animation then brought it forward a bit (by 1.9 seconds). The DrawSVG value now is ‘50% 80%’ meaning 30% of the line is still visible (the start of the line is at 50% and the end of the line is at 80%).

.to([jump, jumpRef], 1, { drawSVG:'50% 80%', ease:Linear.easeNone }, '-=1.9')

And finally, for the jump lines at least, we animate them fully to the end. The DrawSVG value is now ‘100% 100%’ meaning the start of the segment has caught up with the end – we’ve made this happen a bit quicker too at 0.7 seconds.

.to([jump, jumpRef], 0.7, { drawSVG:'100% 100%', ease:Linear.easeNone }, '-=0.9')

Don’t forget the circle ripple on the right – this ‘scales’ up, by 30 for the X axis radius and by 10 for the Y axis radius, just like the left one did and fades out.

.to(circleR, 2, { attr:{rx:'+=30', ry:'+=10' }, alpha:0, ease:Power1.easeOut }, '-=.5'); myTimeline.timeScale(3);

When this animation plays, it will loop forever – when I made this I spent a long time tweaking the offset parameters so that the ripples and jump sections all happened at natural times. And when I finally finished I realized it was far too slow (but thankfully it was uniformly slow) so I added in myTimeline.timescale(3); to speed it up to a more natural looking motion.

The Entire Code

Here’s the full and final code.

var container = document.getElementById('container'); var loader = document.getElementById('loader'); var circleL = document.getElementById('circleL'); var circleR = document.getElementById('circleR'); var jump = document.getElementById('jump'); var jumpRef = jump.cloneNode(); loader.appendChild(jumpRef); TweenMax.set([container, loader], { position: 'absolute', top:'50%', left: '50%', xPercent: -50, yPercent: -50 }) TweenMax.set(jumpRef, { transformOrigin: '50% 110%', scaleY: -1, alpha: 0.05 }) var tl = new TimelineMax({ repeat: -1, yoyo: false }); tl.timeScale(3); tl.set([jump, jumpRef], { drawSVG: '0% 0%' }) .set([circleL, circleR], { attr: { rx: 0, ry: 0, } }) .to([jump, jumpRef], 0.4, { drawSVG: '0% 30%', ease: Linear.easeNone }) .to(circleL, 2, { attr: { rx: '+=30', ry: '+=10' }, alpha: 0, ease: Power1.easeOut }, '-=0.1') .to([jump, jumpRef], 1, { drawSVG: '50% 80%', ease: Linear.easeNone }, '-=1.9') .to([jump, jumpRef], 0.7, { drawSVG: '100% 100%', ease: Linear.easeNone }, '-=0.9') .to(circleR, 2, { attr: { rx: '+=30', ry: '+=10' }, alpha: 0, ease: Power1.easeOut }, '-=.5')

So, that’s it. First of all we drew the graphics we needed in Illustrator (and gave the layers a name for their IDs). Next, we selected them, copied and pasted them into our HTML page (and tidied up some of the ID names and some unnecessary attributes that Illustrator assigns). We then cloned the jump line to create the reflection and, using TweenMax, TimelineMax and the DrawSVGPlugin, we created a TimelineMax instance and sequenced the drawing of the lines and the expanding ripple circles. Then, as with all things, we spent ages tweaking the timings until it looked just right – then when we realized it was too slow we sped it up, leading to our final animation.

Drawing and animating lines has always been a popular effect whether it’s in video motion graphics or on the web and now it’s never been easier to accomplish that effect yourself with the help of GSAP.

Don’t forget to grab your free 1 year membership over at Greensock until April 1, 2015, so sign up now using coupon code CODROPS to get your free “Simply Green” membership or a $50 discount off any other plan.

I hope you have found this article useful – now go and animate some SVGs!