Introduction

En 26 jours de confinement, je viens de finir un alphabet animé de 26 lettres, visible sur https://typotap.jenseign.com, le projet se situe entre patatap, le cédérom Alphabet et d’autres inspirations.
Décortication.

Trois ingrédients

Pour faire votre propre typotap, il vous faut :

  • Environ 26 SVG ;
  • 26 MP3 ;
  • 200 gr de JavaScript.

Les SVG

Pour les SVG, il est nécessaire de comprendre, le dessin en SVG via un logiciel de votre choix (Illustrator, Figma, InkScape, Affinity Designer), la balise <g> et les options de la balise <svg> pour certains cas (preserveAspectRatio).

Les MP3

Par défaut, les animations vont être créées avec une base temporelle en seconde, pour certains sons rythmiques, j’ai réglé les BPM à 120 ou 60 (astuce offerte).

Le JavaScript

On décompose les connaissances :

  • Détecter les événements du clavier — les touches pressées (niveau débutant) ;
  • Charger un SVG en JavaScript (pas débutant, mais facile à écrire avec un exemple) ;
  • Animer le SVG, on utilisera la librairie GSAP (niveau moyen) ;
  • Lire le MP3, on utilisera ToneJS (niveau débutant avec un exemple) ;
  • Retirer le SVG (une ligne :))

Récipient

L’ensemble des ingrédients sera mélangé dans votre navigateur, de préférence à jour et on monte le tout dans une page HTML, avec un peu de CSS.

En pratique

On commence par le clavier et le JavaScript.

See the Pen clavier by Benoît Wimart (@benoitwimart) on CodePen.dark

Puis pour le SVG, on va chercher le fichier (fetch) et si on le trouve (internet ok, le site ok, le fichier existe…), dès qu’il est totalement chargé, on l’insère dans l’élément « #play ».

Fetch permet de charger un fichier venant d’un autre site, mais pour des raisons de sécurité, les Blocage de requêtes multiorigines (Cross-Origin Request) sont courantes (ici jenseign.com est bloqué sur codepen, mais pas « s3-us-west‑2.amazonaws.com/s.cdpn.io ».

See the Pen fetch svg by Benoît Wimart (@benoitwimart) on CodePen.dark

Les deux ensemble (en supposant que le svg est dans le même dossier) :

const play = document.querySlector('#play');
 
function load(letter){
  fetch(letter+'.svg') // concatenation, je charge a.svg ou b.svg … z.svg 
    .then(function(response){
      if(response.ok){
        response.text().then(function(svg){
          play.insertAdjacentHTML("beforeend", svg);
        });
      }
  });
}
 
document.addEventListener('keyup',function(e){
  load(e.key); // une fonction qui charge 
});
Attention, pas mal fonctionnalités JavaScript nécessitent un serveur pour marcher. Trois solutions, mettre en ligne, installer un serveur local ou utiliser l’extension live server de VS Code. Si votre adresse dans le navigateur commence par « file:/// », vous devez résoudre d’abord ce problème.

J’anime

Voici l’avant dernière étape, l’animation, il faut connaitre les fonctions, GSAP et l’overlap (la superposition) en CSS avec Grid.
L’ensemble est ici sur Repl.it.

C’est ici qu’il faut jongler entre la créatvité, le SVG, GSAP et le logiciel de musique (Audacity pour voir le timing).
const play = document.querySelector('#play');
 
function load(letter){
  fetch(letter+'.svg') // concatenation, je charge a.svg ou b.svg … z.svg 
    .then(function(response){
      if(response.ok){
        response.text().then(function(svg){
          // insertion professionnelle
          play.insertAdjacentHTML("beforeend", svg);
          // on ajoute un id avec la lettre et la date en ms
          // depuis 1970 pour le rendre unique
          // ex : r1586771234272 
          // https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Date/now
          play.lastElementChild.id = letter + Date.now(); 
          // la fonction qui animera
          // je lui donne la lettre, l'élément et l'id
          anim(letter,play.lastElementChild,play.lastElementChild.id);
 
        });
      }
  });
}
 
document.addEventListener('keyup',function(e){
  load(e.key); // une fonction qui charge 
});
 
function anim(letter,el,id){
    // je récupère la letter, l'élément et l'id pour gsap et le switch 
    // voir la doc mdn sur le switch/case 
    switch(letter) {
      case 'r':
          // j'attache une timeline à l'élément
          el.tl_= gsap.timeline();
          // gsap to
          el.tl_.to('body',{backgroundColor:'#F90'});
          // '#'+id+' .r' sera '#r1586771234272 .r'
          el.tl_.to('#'+id+' .r',{duration:.2,rotation:-15,transformOrigin:'left bottom',repeat:1,yoyo:true,ease:'power1.out'},0);
          el.tl_.to('#'+id,{scale:1.1,transformOrigin:'.5 .5',opacity:0,duration:2,ease:'power1'},0);
          // on enchaine et efface l'élément quand l'animation est finie :) 
          el.tl_.call(function(){el.remove()});
      break;
 
      // avec les autres lettres
      /*
      case 's':
          el.tl_= gsap.timeline();
          el.tl_.to('body',{backgroundColor:'#000'});
          el.tl_.to('#'+id+' .s',{duration:.2,rotation:-15,transformOrigin:'left bottom',repeat:1,yoyo:true,ease:'power1.out'},0);
          el.tl_.to('#'+id,{scale:1.1,transformOrigin:'.5 .5',opacity:0,duration:2,ease:'power1'},0);
          el.tl_.call(function(){el.remove()});
      break;
      */
    }
}

Let’s the musique play

J’ajoute la librairie dans la page d’HTML.
Je connnais peu ToneJS, mais le sampler permet de charger nos sons et avoir une polyphonie.
Pour TypoTap, après chargement, j’ajoute l’écouteur d’événement du clavier.

Voici la demo sur repl.it

Le code JavaScript :

const play = document.querySelector('#play');
 
/* TONE JS */
const alphabet = new Tone.Sampler({
  "F3":"r.mp3", // , <- virgule
  "G3":"s.mp3" // on liste les sons ici
  }, // <- virgule
  function(){ 
    // quand les mp3 sont chargés, on ajoute l'écouteur de clavier
    // ce bout de code était plus bas
    document.addEventListener('keyup',function(e){
      load(e.key); // une fonction qui charge 
    });
  }
).toMaster(); // <- un truc de toneJS pour envoyer le son
 
function load(letter){
  fetch(letter+'.svg') // concatenation, je charge a.svg ou b.svg … z.svg 
    .then(function(response){
      if(response.ok){
        response.text().then(function(svg){
          // insertion professionnelle
          play.insertAdjacentHTML("beforeend", svg);
          // on ajoute un id avec la lettre et la date en ms
          // depuis 1970 pour le rendre unique
          // ex : r1586771234272 
          // https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Date/now
          play.lastElementChild.id = letter + Date.now(); 
          // la fonction qui animera
          // je lui donne la lettre, l'élément et l'id
          anim(letter,play.lastElementChild,play.lastElementChild.id);
 
        });
      }
  });
}
 
 
 
function anim(letter,el,id){
    // je récupère la letter, l'élément et l'id pour gsap et le switch 
    // voir la doc mdn sur le switch/case 
    switch(letter) {
      case 'r':
          /* Tone JS en action */
          alphabet.triggerAttack("F3");
 
          // j'attache une timeline à l'élément
          el.tl_= gsap.timeline();
          // gsap to
          el.tl_.to('body',{backgroundColor:'#F90'});
          // '#'+id+' .r' sera '#r1586771234272 .r'
          el.tl_.to('#'+id+' .r',{duration:.2,rotation:-15,transformOrigin:'left bottom',repeat:1,yoyo:true,ease:'power1.out'},0);
          el.tl_.to('#'+id,{scale:1.1,transformOrigin:'.5 .5',opacity:0,duration:2,ease:'power1'},0);
          // on enchaine et efface l'élément quand l'animation est finie :) 
          el.tl_.call(function(){el.remove()});
      break;
 
      // avec les autres lettres
      /*
      case 's':
          el.tl_= gsap.timeline();
          el.tl_.to('body',{backgroundColor:'#000'});
          el.tl_.to('#'+id+' .s',{duration:.2,rotation:-15,transformOrigin:'left bottom',repeat:1,yoyo:true,ease:'power1.out'},0);
          el.tl_.to('#'+id,{scale:1.1,transformOrigin:'.5 .5',opacity:0,duration:2,ease:'power1'},0);
          el.tl_.call(function(){el.remove()});
      break;
      */
    }
}