Pular para o conteúdo principal

GOOD MOOD parte 2: animando as letras

· Leitura de 9 minutos

Na segunda parte, animo as letras e defino suas posições e cores.


GOOD MOOD (série de 6 partes)
  1. Introdução
  2. Desenhando as letras
  3. Animando as letras
  4. Aplicando filtros
  5. Proporção de pixel
  6. Conclusão

Animando as letras​

Atributos do elemento animate​

attributeName​

Nome do atributo que mudará durante a animação, o atributo d no caso desta animação.

values​

Sequência de valores usada no decorrer da animação. No caso desta animação, são 3 valores do atributo d.

Para as letras da primeira fileira: versão normal, versão esticada e versão normal novamente. Na segunda fileira: versão esticada, versão normal e versão esticada novamente.

calcMode​

Modo de interpolação (processo que calcula os valores intermediários da animação), que é spline. Permite usar curvas de Bézier para definir a função de tempo, possibilitando transições suaves.

keyTimes​

Sequência de valores que define o ritmo da animação, cada valor fica entre 0 e 1. Com calcMode spline, para cada valor de values, deve existir um valor de keyTimes.

No caso desta animação, 0; 0.5; 1. Ou seja, o primeiro valor de values é usado no início da animação, o segundo valor é usado na metade da animação, e o terceiro valor é usado no fim da animação.

keySplines​

Sequência de valores que define as curvas de Bézier (x1, y1, x2, y2) usadas nos intervalos entre os valores do atributo keyTimes.

No caso desta animação, 0.45, 0.05, 0.55, 0.95; 0.45, 0.05, 0.55, 0.95 (duas curvas iguais). Ou seja, entre 0; 0.5 o primeiro valor é usado, e entre 0.5; 1 o segundo valor é usado.

begin​

Define quando a animação deve começar. Usei para atrasar o início da animação de cada coluna para criar o movimento de onda.

dur​

A duração da animação, que é 1s.

repeatCount​

Número de repetições, que é indefinite (repete-se indefinidamente).

Atributos desta animação​

Deixei o atributo d do elemento path vazio, visto que ele é definido no atributo values do elemento animate. Os únicos atributos do elemento animate que mudam de uma letra para outra são values e begin, os demais atributos têm o mesmo valor em todas as letras.

<svg viewBox="0 0 10 20">  <path d="">    <animate      attributeName="d"      begin="valor baseado na coluna"      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="desenho de letra; desenho de letra; desenho de letra"    />  </path></svg>

Nas visualizações seguintes não defini o atributo begin, porque ainda estava lidando individualmente com cada letra. Mostro a posição final na seção Definindo as posições.

Nestas seções usei um viewBox que comporta apenas uma letra:

<svg viewBox="0 0 10 20" width="200">  <!-- demais elementos entrarão aqui --></svg>

Primeira fileira​

info

Em cada visualização, omiti os elementos svg e path que se encontrariam em volta do elemento animate, assim como seus demais atributos, para manter o código conciso.

<animate  values="    versão normal;    versão esticada;    versão normal  "/>

Letra 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  "/>

Letra 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  "/>

Letra 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  "/>

Segunda fileira​

info

Em cada visualização, omiti os elementos svg e path que se encontrariam em volta do elemento animate, assim como seus demais atributos, para manter o código conciso.

<animate  values="    versão esticada;    versão normal;    versão esticada  "/>

Letra 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  "/>

Letra 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  "/>

Letra 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  "/>

Definindo as posições​

Elementos defs e use​

Defini o atributo id de cada elemento path e os coloquei dentro do elemento defs, para que depois pudesse referenciá-los com elementos use pelo atributo href.

Com o elemento use, defini a posição de cada letra com os atributos x e y, seguindo a grade. Pus um número no fim do valor do atributo id das letras que se repetiam, pois eles devem ser únicos.

<!--  omiti os atributos dos elementos animate  para manter o código conciso --><svg viewBox="0 0 63 51">  <defs>    <!-- primeira fileira -->    <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>    <!-- segunda fileira -->    <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>  <!-- primeira fileira -->  <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" />  <!-- segunda fileira -->  <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>

Definindo o atributo begin​

Seguindo a animação original, quando a primeira coluna está esticada para cima, a última coluna está esticada para baixo. Como a animação tem 1s, defini que a primeira coluna tem o atributo begin como -1 (valores negativos fazem com que não exista delay ao iniciar a animação), e a última coluna como -0.5. Ou seja, quando a primeira coluna completa um clico de animação, a última coluna completa metade de um ciclo.

Para obter o valor do atributo begin das demais colunas, calculei o intervalo de tempo que deveria existir entre o início da animação de cada uma das 4 colunas: 0.5 / 3 ≈ 0.1666. Com isso, calculei o valor do atributo begin de cada coluna:

  • Primeira coluna: -1
  • Segunda coluna: -1 + 0.1666 ≈ -0.8333
  • Terceira coluna: -0.8333 + 0.1666 ≈ -0.6666
  • Quarta coluna: -0.6666 + 0.1666 ≈ -0.5
<!--  omiti os demais atributos dos elementos animate  para manter o código conciso --><svg viewBox="0 0 63 51">  <defs>    <!-- primeira fileira -->    <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>    <!-- segunda fileira -->    <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>  <!-- primeira fileira -->  <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" />  <!-- segunda fileira -->  <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>

Definindo cores​

Defini as cores de cada letra no elemento use, e a cor do plano de fundo com um elemento rect. A ordem dos elementos importa, o rect deve ser desenhado antes das letras, do contrário, o rect seria desenhado por cima das letras.

<div class="wrapper">  <div class="container">    <svg viewBox="0 0 63 51">      <defs>        <!--          omiti o conteúdo do elemento defs          para manter o código conciso         -->      </defs>      <!-- fundo preto -->      <rect width="63" height="51" fill="#000" />      <!-- primeira fileira -->      <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" />      <!-- segunda fileira -->      <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>

Para centralizar a animação, adicionei CSS.

/* reset simples */*,*::before,*::after {  box-sizing: border-box;  margin: 0;  padding: 0;}/* o wrapper tem a altura do viewport */.wrapper {  display: flex;  min-height: 100vh;}/* a animação fica no centro da tela */.container {  margin: auto;  width: 800px;  max-width: 100%;}

Conclusão​

Tendo a animação feita e as cores definidas, segui para os filtros: GOOD MOOD parte 3: aplicando filtros.

Leitura recomendada​