HowTo: Animate SVG waves in Framer JS

Piotr Kuklo
Framer
Published in
4 min readSep 27, 2016

--

In this article I will explain the simplest way to animate and control SVG waves in Framer JS. To explain the details, I will use this prototype:

Take a look at the final prototype

To make the animation sweet and smooth, I had to take a couple of steps:

Step 0: Understanding how sine waves work

First, I needed to remind myself what those sine equations were about. I learnt from edu websites with nice explanations and then decided to keep the same naming of the parameters as an official equation to make my life easier. I wrote what each of the parameters change in the wave shape and then I started to play a “what if” game with the parameters. It looked similar to this:

So to make points that describe the wave shape I used those lines (+100 at the end moves a wave by 100pt down):

for t in [0..STEPS]
yPos = @Amplitude*Math.sin(@freq*t+@phase*SPEED)+100
xPos = t

Step 1: Visualising a sine wave with SVG

I found a couple of interesting examples on Framer JS’s website, but the one that was most useful was the prototype by Josh Puckett. I tweaked it to fit my own purpose and now it works like this:

  1. Clear a points array from old points.
  2. Create a new set of points that are slightly moved to the left.
  3. Render those points by putting a points array into:
<svg points=’…’></svg>

Step 2: Making it move!

Ok, all good but how do we move the points slightly to the left? Let’s look again at the “What if” exploration. Have you noticed that when we modify a phase value, the wave is moving to the left? That is how we can make it move with code. After adding every point, a phase value is incremented by 1:

yPos = @Amplitude*Math.sin(@freq*t+@phase*SPEED)+100
xPos = t
@points.push(xPos,yPos)
@phase+=1

Step 3: Making an infinite smooth animation with an organic feel

To make the waves move all the time I created a layer amplitudeSquare and wrote two animations: animAmplitudeUp and animAmplitudeDown. Those animations make amplitudeSquare move in an infinite loop and the waves react with every change of the x value of this layer:

amplitudeSquare.on “change:x”, ->
tempAmp = this.x
for wave in waveArray
wave.clearPoints()
wave.update tempAmp
wave.render()

To add a more organic feel I connected the x position of amplitudeSquare with the wave’s amplitude in an update function:

Step 4: Creating a Wave class

Now, when one wave is moving on my screen in a sweet animation, I want to play with classes and objects to add a new object with less effort. A Wave class extends a Layer class and has some additional attributes and functions that control its movement:

class Wave extends Layer
constructor: (options) ->
super _.defaults options,
width: 300
height: 100
@Amplitude = 15
@freq = 0.01/Math.PI
@phase = 1/Math.PI
@points = []
@stroke = 4
#Wave Functions:
render: -> #renders svg wave from the array
clearPoints: -> #clears the array
update: (ampToUpdate) -> #takes amplitudeSquare position and updates the wave's amplitude value

Step 5: Writing a simple ON/OFF controller

To check if Wave class is working properly I pushed a couple of waves into an array and wrote a tricky controller. Controller doesn’t change any of the Wave’s parameters (only the one that Wave extends from Layer class — opacity, y position and rotation). Instead of that, it changes the position of amplitudeSquare to 1 by animAmplitudeZero animation and that indirectly influences the waves:

Your Step = Additional advice

Getting through people’s code is the best practice. Sometimes it is hard to build something from scratch but looking at others’ solutions can inspire us and help us overcome our obstacles. I always start a project by looking at the existing solutions I can modify or reuse.

I encourage you to take a look at the prototype and open it in Framer. In this HOWTO I didn’t describe every detail so reading the code can be quite useful. If you find anything that can be used in your project — don’t hesitate, copy/paste it.

I hope you find this article interesting and please let me know what you think about it in the comments section below.

--

--