Skip to main content

GOOD MOOD part 2: animating the letters

· 9 min read

In the second part, I animate the letters and I define their positioning and colors.


Animating the letters

animate element's attributes

attributeName

Name of the attribute that will change during the animation, the d attribute in this animation.

values

List of values used throughout the animation. In this animation, the d attribute assumes 3 values.

In the first row letters: normal version, stretched version and normal version again. In the second row: stretched version, normal version and stretched version again.

calcMode

Interpolation mode (process that calculates the animation's intermediate values), which is spline in this animation. It allows the use of Bézier curves to define the time function, enabling smooth transitions.

keyTimes

List of values that defines the animation's rhythm, each value ranges between 0 and 1. With calcMode spline, for every values value, there must be a keyTimes value.

In this animation, the list is 0; 0.5; 1. That is, the first value of values is used at the beginning of the animation, the second value is used at the middle of the animation, and the third value is used at the end of the animation.

keySplines

List of values defining the Bézier curves (x1, y1, x2, y2) used in the intervals between the keyTimes attribute's values.

In this animation, the list is 0.45, 0.05, 0.55, 0.95; 0.45, 0.05, 0.55, 0.95 (the same curve on both values). That is, between 0; 0.5 the first value is used, and between 0.5; 1 the second value is used.

begin

Defines when the animation should start. I used it to delay the start of each column's animation to create the wave motion.

dur

The animation duration, which is 1s in this animation.

repeatCount

Number of repetitions, which is indefinite in this animation.

Attributes of this animation

I left the path element's d attribute empty, as it is defined in the animate element's values attribute. The only animate element's attributes that change from one letter to another are values and begin, the other attributes have the same value for all letters.

<svg viewBox="0 0 10 20">  <path d="">    <animate      attributeName="d"      begin="column based value"      dur="1s"      repeatCount="indefinite"      calcMode="spline"      keySplines="0.45, 0.05, 0.55, 0.95; 0.45, 0.05, 0.55, 0.95"      keyTimes="0; 0.5; 1"      values="d commands; d commands; d commands"    />  </path></svg>

In the following views I didn't set the begin attribute, because I was still dealing with each letter individually. I show the final position in the section Positioning.

In these sections I used a viewBox that holds only one letter:

<svg viewBox="0 0 10 20" width="200">  <!-- other elements go here --></svg>

First row

info

In each view, I omitted the svg and path elements that would wrap the animate element, as well as its other attributes, to keep the code concise.

<animate  values="    regular version;    stretched version;    regular version  "/>

Letter G

<animate  values="    M0,4 Q0,0 4,0 L6,0 Q10,0 10,4 L10,4.6 L6,4.6 L6,4 C6,3 4,3 4,4 L4,6 C4,7 6,7 6,6 L5,6 L5,5 L10,5 L10,10 L7,10 L6.6,9 Q6,10 4,10 Q0,10 0,6z;    M0,4 Q0,0 4,0 L6,0 Q10,0 10,4 L10,14.6 L6,14.6 L6,4 C6,3 4,3 4,4 L4,16 C4,17 6,17 6,16 L5,16 L5,15 L10,15 L10,20 L7,20 L6.6,19 Q6,20 4,20 Q0,20 0,16z;    M0,4 Q0,0 4,0 L6,0 Q10,0 10,4 L10,4.6 L6,4.6 L6,4 C6,3 4,3 4,4 L4,6 C4,7 6,7 6,6 L5,6 L5,5 L10,5 L10,10 L7,10 L6.6,9 Q6,10 4,10 Q0,10 0,6z  "/>

Letter O

<animate  values="    M0,4 Q0,0 4,0 L6,0 Q10,0 10,4 L10,6 Q10,10 6,10 L4,10 Q0,10 0,6 L4,6 C4,7 6,7 6,6 L6,4 C6,3 4,3 4,4 L4,6 L0,6z;    M0,4 Q0,0 4,0 L6,0 Q10,0 10,4 L10,16 Q10,20 6,20 L4,20 Q0,20 0,16 L4,16 C4,17 6,17 6,16 L6,4 C6,3 4,3 4,4 L4,16 L0,16z;    M0,4 Q0,0 4,0 L6,0 Q10,0 10,4 L10,6 Q10,10 6,10 L4,10 Q0,10 0,6 L4,6 C4,7 6,7 6,6 L6,4 C6,3 4,3 4,4 L4,6 L0,6z  "/>

Letter D

<animate  values="    M0,0 L6,0 Q10,0 10,4 L10,6 Q10,10 6,10 L0,10 L0,7 L4,7 Q6,7 6,6 L6,4 Q6,3 4,3 L4,7 L0,7z;    M0,0 L6,0 Q10,0 10,4 L10,16 Q10,20 6,20 L0,20 L0,17 L4,17 Q6,17 6,16 L6,4 Q6,3 4,3 L4,17 L0,17z;    M0,0 L6,0 Q10,0 10,4 L10,6 Q10,10 6,10 L0,10 L0,7 L4,7 Q6,7 6,6 L6,4 Q6,3 4,3 L4,7 L0,7z  "/>

Second row

info

In each view, I omitted the svg and path elements that would wrap the animate element, as well as its other attributes, to keep the code concise.

<animate  values="    stretched version;    regular normal;    stretched version  "/>

Letter M

<animate  values="    M0,0 L4,0 L5,6 L6,0 L10,0 L10,20 L7,20 L7,7 L6,20 L4,20 L3,7 L3,20 L0,20z;    M0,10 L4,10 L5,14 L6,10 L10,10 L10,20 L7,20 L7,15 L6,20 L4,20 L3,15 L3,20 L0,20z;    M0,0 L4,0 L5,6 L6,0 L10,0 L10,20 L7,20 L7,7 L6,20 L4,20 L3,7 L3,20 L0,20z  "/>

Letter O

<animate  values="    M0,4 Q0,0 4,0 L6,0 Q10,0 10,4 L10,16 Q10,20 6,20 L4,20 Q0,20 0,16 L4,16 C4,17 6,17 6,16 L6,4 C6,3 4,3 4,4 L4,16 L0,16z;    M0,14 Q0,10 4,10 L6,10 Q10,10 10,14 L10,16 Q10,20 6,20 L4,20 Q0,20 0,16 L4,16 C4,17 6,17 6,16 L6,14 C6,13 4,13 4,14 L4,16 L0,16z;    M0,4 Q0,0 4,0 L6,0 Q10,0 10,4 L10,16 Q10,20 6,20 L4,20 Q0,20 0,16 L4,16 C4,17 6,17 6,16 L6,4 C6,3 4,3 4,4 L4,16 L0,16z  "/>

Letter D

<animate  values="    M0,0 L6,0 Q10,0 10,4 L10,16 Q10,20 6,20 L0,20 L0,17 L4,17 Q6,17 6,16 L6,4 Q6,3 4,3 L4,17 L0,17z;    M0,10 L6,10 Q10,10 10,14 L10,16 Q10,20 6,20 L0,20 L0,17 L4,17 Q6,17 6,16 L6,14 Q6,13 4,13 L4,17 L0,17z;    M0,0 L6,0 Q10,0 10,4 L10,16 Q10,20 6,20 L0,20 L0,17 L4,17 Q6,17 6,16 L6,4 Q6,3 4,3 L4,17 L0,17z  "/>

Positioning

defs and use elements

I defined the id attribute of each path element and placed them inside the defs element, so that later I could reference them with use elements by the href attribute.

With the use element, I defined the position of each letter with the x and y attributes, following the grid. I put a number at the id attribute value's end of repeating letters, as they must be unique.

<!--  I omitted the animate elements' attributes  to keep the code concise --><svg viewBox="0 0 63 51">  <defs>    <!-- first row -->    <path d="" id="letter-g"><animate /></path>    <path d="" id="letter-o-1"><animate /></path>    <path d="" id="letter-o-2"><animate /></path>    <path d="" id="letter-d-1"><animate /></path>    <!-- second row -->    <path d="" id="letter-m"><animate /></path>    <path d="" id="letter-o-3"><animate /></path>    <path d="" id="letter-o-4"><animate /></path>    <path d="" id="letter-d-2"><animate /></path>  </defs>  <!-- first row -->  <use href="#letter-g" x="10" y="10" />  <use href="#letter-o-1" x="21" y="10" />  <use href="#letter-o-2" x="32" y="10" />  <use href="#letter-d-1" x="43" y="10" />  <!-- second row -->  <use href="#letter-m" x="10" y="21" />  <use href="#letter-o-3" x="21" y="21" />  <use href="#letter-o-4" x="32" y="21" />  <use href="#letter-d-2" x="43" y="21" /></svg>

Defining the begin attribute

Following the original animation, when the first column is stretched up, the last column is stretched down. As the animation has 1s, I set the first column's begin attribute value as -1 (negative values mean that there is no delay when starting the animation), and the last column as -0.5. That is, when the first column completes one animation cycle, the last column completes half a cycle.

To obtain the begin attribute's value of the other columns, I calculated the time interval that should exist between the animation's beginning of each of the 4 columns: 0.5 / 3 ≈ 0.1666. With that, I calculated the value of the begin attribute of each column:

  • First column: -1
  • Second column: -1 + 0.1666 ≈ -0.8333
  • Third column: -0.8333 + 0.1666 ≈ -0.6666
  • Fourth column: -0.6666 + 0.1666 ≈ -0.5
<!--  I omitted the animate elements' other attributes  to keep the code concise --><svg viewBox="0 0 63 51">  <defs>    <!-- first row -->    <path d="" id="letter-g">      <animate begin="-1" />    </path>    <path d="" id="letter-o-1">      <animate begin="-0.8333" />    </path>    <path d="" id="letter-o-2">      <animate begin="-0.6666" />    </path>    <path d="" id="letter-d-1">      <animate begin="-0.5" />    </path>    <!-- second row -->    <path d="" id="letter-m">      <animate begin="-1" />    </path>    <path d="" id="letter-o-3">      <animate begin="-0.8333" />    </path>    <path d="" id="letter-o-4">      <animate begin="-0.6666" />    </path>    <path d="" id="letter-d-2">      <animate begin="-0.5" />    </path>  </defs>  <!-- first row -->  <use href="#letter-g" x="10" y="10" />  <use href="#letter-o-1" x="21" y="10" />  <use href="#letter-o-2" x="32" y="10" />  <use href="#letter-d-1" x="43" y="10" />  <!-- second row -->  <use href="#letter-m" x="10" y="21" />  <use href="#letter-o-3" x="21" y="21" />  <use href="#letter-o-4" x="32" y="21" />  <use href="#letter-d-2" x="43" y="21" /></svg>

Colors

I set the colors of each letter in the use element, and the background color with a rect element. The order of elements matters, the rect must be drawn before the letters, otherwise the rect would be drawn on top of the letters.

<div class="wrapper">  <div class="container">    <svg viewBox="0 0 63 51">      <defs>        <!--          I omitted the defs element's code          to keep the code concise         -->      </defs>      <!-- background -->      <rect width="63" height="51" fill="#000" />      <!-- first row -->      <use href="#letter-g" x="10" y="10" fill="#FFFFFF" />      <use href="#letter-o-1" x="21" y="10" fill="#FFFFFF" />      <use href="#letter-o-2" x="32" y="10" fill="#FFFFFF" />      <use href="#letter-d-1" x="43" y="10" fill="#FFFFFF" />      <!-- second row -->      <use href="#letter-m" x="10" y="21" fill="#FFB200" />      <use href="#letter-o-3" x="21" y="21" fill="#006BF5" />      <use href="#letter-o-4" x="32" y="21" fill="#FD002D" />      <use href="#letter-d-2" x="43" y="21" fill="#FF769F" />    </svg>  </div></div>

To center the animation, I added CSS.

/* simple reset */*,*::before,*::after {  box-sizing: border-box;  margin: 0;  padding: 0;}/* the wrapper has the viewport's height */.wrapper {  display: flex;  min-height: 100vh;}/* the animation is centered */.container {  margin: auto;  width: 800px;  max-width: 100%;}

Conclusion

Having the animation done and the colors defined, I proceeded to the filters: GOOD MOOD part 3: applying filters.

Recommended reading