DEV Community

loading...

Learning SVG animation to spice up my GitHub Profile

pushkar8723 profile image Pushkar Anand Originally published at abstracted.in Updated on ・7 min read

TLDR: I created an animated SVG for my GitHub profile, check it out here.

So it all started with GitHub releasing a feature to add a Readme to your profile to showcase all the awesome work that you have done / been doing. And lo and behold, people figured out that it can be used to add GIFs to their profile. 🥳

But I was like, GIFs are so 2010 and SVGs are the new 💩. Only one problem, I don't know a thing about SVGs. I mean yes I have used it for icons and some illustrations. Sometimes generated one from some utility and snapped it onto a page. But I have never delved into how to create one from scratch and add animation to it.

With nothing better to do, I started googling and was surprised to find that MDN has elaborate documentation on SVG elements. Turns out, it is quite simple to add basic shapes. There are tags like rect, circle, polygon, line, and polyline, etc. Then simply write CSS to animate it.

Neat! 👍

So now I can just move a logo on the screen and have boomers look at it for hours! 💪

office reference

But I digress. Back to animating SVG. Above mentioned shapes might be more than sufficient for a creative person to come up with some really cool illustration. But my creativity is fairly limited and so I decided to do a moving wave. And to compensate for my lack of creativity, I learned another tag called path, which will help me create this wave. 🌊

The Idea 🤓

The idea was simple. Create multiple moving waves, each at a different speed, and make them a little see-through. The transparency will make the area darker where the waves intersect and thus there will be multiple shades of the color.

For the size of the banner, I settled for 1440 x 320 as I like the aspect ratio. It's not too big but is big enough to add context. Given that on GitHub it would show up in a smaller area, I can be sure that there is enough space left for other things that I might want to add.

<path />

So, I started by learning how to create a path. Which was quite simple. The path tag has a d attribute. It was not hard to get 😉. There are 6 different types of commands.

  • MoveTo
  • LineTo
  • Cubic Bézier Curve
  • Quadratic Bézier Curve
  • Elliptical Arc Curve
  • Close path

We only need to learn the first three. Each command is denoted with a letter followed by attributes which are
points (x-y coordinates).

move

MoveTo command is denoted by letter M or m followed by the point. So a M10,10 would move the current position to the point 10,10.

line

Similarly, LineTo has three commands.
L or l creates a line from the current position to the given point. For example, L10,10 would create a line from the current position to 10,10. H or h would create a horizontal line to the given x coordinate. And lastly, V or v would create a vertical line to the given y coordinate.

Cubic Bézier Curve is slightly more complex. It is denoted by letter C or c and takes 3 points as arguments.

Cubic Bézier Curve

So, the current position is the start point. The line from the current position to x1 y1 point defines the tangent to the curve at the start position. And the line from x2 y2 to x3 y3 defines tangent at the finish position. And x3 y3 is the endpoint. To know more about Cubic Bézier Curve refer to this blog post which I find short but descriptive. You can also refer MDN Tutorial on the SVG path to learn more.

To solidify what we learned right now, lets decode the following SVG.

<svg
  viewbox="0 0 100 100"
  width="100" height="100" 
  xmlns="http://www.w3.org/2000/svg">
  <path
    d="M10,10 V50 C10,90,90,90,90,50 V10 H10 V50"
  />
</svg>

The code above results in SVG shown below. For clarity, I have put a green border around the image.

example svg

Our path starts at 0,0 and the first command M10,10 moves our point to 10,10. Then the second command V50 creates a vertical path to 10,50. Next C10,90,90,90,90,50 create a curve with 10,90 and 90,90 as our reference points and 90,50 is the endpoint. Then V10 creates a path to 90,10. Next, H10 creates a path to 10,10 and finally V50 closes the path and we get our final image. Simple right? 👌

Implementation ✍️

steps

I divided the image into four quadrants and then planned to have a curve in the second and third quadrants, as shown in the first section in the image above. Then I can slightly move the tangents inwards to dampen the curve. Finally, I closed the path using lines. I moved the center point slightly to have curves that are slightly different. But making sure that the angle the tangents make with the vertical axis is the same. This ensures that the curve looks continuous when I animate it. Finally, I ended up with the path as described below.

<path d="M0,160 C320,300,420,300,740,160 C1060,20,1120,20,1440,160 V0 H0" />

If you are having trouble with understanding the path described above, look at the last section in the image above. I have colour-coded each part of the path to make it more clear. You can also compare it with the section just above it to get an understanding of the points. If you were able to follow me till now, then we already sailed through the difficult waters. 😁

<defs /> and <use />

Although, we can now just copy-paste the above path and create other waves with slight variations and call it a day. I want to introduce defs and use tag, that will help us do all these in a much more readable way. defs can be used to store graphical elements like path and then can be used later using use tag.

All we need to do is give an id to our path and put it inside defs tag and then use it using href attribute in use tag as described below.

<svg
  viewbox="0 0 1440 320"
  width="1440" height="320" 
  xmlns="http://www.w3.org/2000/svg">
  <defs>
    <path
      id='sineWave'
      d="M0,160 C320,300,420,300,740,160 C1060,20,1120,20,1440,160 V0 H0"
    />
  </defs>
  <use href="#sineWave" />
</svg>

Right now a black wave is being rendered. To fix that we use fill and fill-opacity attribute in path. So our updated path becomes as described below.

<path
  fill="#0099ff" fill-opacity="0.2"
  id='sineWave'
  d="M0,160 C320,300,420,300,740,160 C1060,20,1120,20,1440,160 V0 H0"
/>

Animation 🤤

If you are already familiar with CSS animation, this section will be a cakewalk for you. So the idea is very simple. Have two of the waves (that we created above) stacked horizontally and then simply translate them from 0 to 100%. Rinse and repeat. Something like below.

final

Here the black box represents the viewport of the user.

To achieve this, we add another use tag but with x attribute set to -100%. Apply, wave class to both of these use tags. And create an animation where we translate x from 0% to 100% and apply this animation to our wave class.

<svg
  viewbox="0 0 1440 320"
  width="1440" height="320" 
  xmlns="http://www.w3.org/2000/svg">
  <defs>
    <style type="text/css">
      .wave {
        animation: wave 8s linear infinite;
      }
      @keyframes wave {
        0% {
          transform: translateX(0%);
        }
        100% {
          transform: translateX(100%);
        }
      }
    </style>
    <path
      fill="#0099ff" fill-opacity="0.2"
      id='sineWave'
      d="M0,160 C320,300,420,300,740,160 C1060,20,1120,20,1440,160 V0 H0"
    />
  </defs>
  <use class="wave" href="#sineWave"/>
  <use class="wave" x="-100%" href="#sineWave"/>
</svg>

Finally, I added two more similar waves, the only difference is that I used scaleY in transform CSS property to have a different amplitude of the waves. You can check out the final SVG on CodePen.

Bonus Tips 🤗

I also added a few texts on the banner. This could have been simple as SVG supports Google Fonts but the content security policy of GitHub doesn't allow fonts to be downloaded from external sources. Thus, I used this utility to create an SVG path for me which I copied in my final SVG. Check it out on my GitHub Profile.

Conclusion 👨‍💻

I barely scratched the surface of SVG animation but was able to create something which I think is cool. Was there a better way to do it? Is there some other interesting thing that I should explore? Do let me know by commenting below or send me a tweet on twitter.

Update

My friend showed me SVG Path Visualizer which I find quite useful to visualize the change path.

We also found that there are many example SVGs present online which we can easily tweak using defs and use tags. To test this out, I tweaked this codepen example and created a banner for him which you can checkout on his GitHub profile.

Discussion

pic
Editor guide
Collapse
delta_maniac profile image
Harikrishnan Menon

This animation looks so cool.
Awesome 👍

Collapse
perpetual_education profile image
perpetual . education

This is really cool. Isn't it really just a CSS animation though? The SVG doesn't really animate so much as it's bounding box.

Collapse
pushkar8723 profile image
Pushkar Anand Author

Yes, you are correct. What I used for animation here is just CSS. However, I can put the entire code in a .svg file and can use it like any other image type. The CSS will not leak out of the image and the SVG will hold its animation. I can use this SVG file as a background to any of my DOM elements. And I can also apply any CSS transformation on it. Just like how I would do to any other image. Does that sound fair enough to call it an animated SVG?

Collapse
perpetual_education profile image
perpetual . education

It is definitely and SVG that is moving - and it's a really neat way to get that kinda of feel into a markdown file.

Collapse
annietaylorchen profile image
Annie Taylor Chen

It looked really nice on your github :)