## Fluidité, performance et contrôle : les clés de l’animation.

Dans le cadre d’un projet de jeu WebGL, on avait à animer des personnages en 2D. En utilisant l’éditeur d’animation [Rive](https://rive.app/), on a créé des animations relativement complexes en appliquant un squelette aux personnages.

Pour l’intégration finale, on aurait pu utiliser [la librairie web de Rive](https://github.com/rive-app/rive-wasm), mais elle n’offrait pas une grande marge de manœuvre : nos animations devaient être intégrées dans une scène existante [Threejs](https://threejs.org/). C’est tout ce qu’il nous fallait pour qu’on décide de mettre en place un _player_ de _spritesheets_.

### Spritesheets, mais encore?

Une _spritesheet_ est une image composée de plusieurs images plus petites (sprites) qui décomposent une animation. Le fait d’avoir plusieurs petites images en une seule grande image améliore les performances, réduit l'utilisation de la mémoire et le temps de chargement initial de l’appli, du site ou du jeu, ainsi que le nombre d’appels serveur.

Il existe plusieurs logiciels qui permettent de créer facilement des _spritesheets_ tels que [TexturePacker](https://www.codeandweb.com/texturepacker) ou la version équivalente gratuite [Free Texture Packer](http://free-tex-packer.com/). Ces logiciels peuvent exporter le fichier image final avec un fichier JSON qui dresse les positions, rotations et dimension de chaque image dans la _spritesheet_. Ce sont des données cruciales pour le _player_, qui saura positionner la texture au bon endroit.

### Bonjour, WebGLSpritesheetPlayer

Le _player_ hérite de la classe [Sprite](https://threejs.org/docs/#api/en/objects/Sprite) de ThreeJS pour que l’animation fasse toujours face à la caméra. Pour obtenir un outil flexible qui répondait à de multiples utilisations, on a intégré les propriétés ci-dessous.

```javascript

```

Le _player_ conserve les bonnes dimensions de la texture pour ne pas déformer l’animation. Il supporte plusieurs options de formats : séquence d’images, et un ou plusieurs spritesheets avec leurs fichiers JSON associés. On a également ajouté quelques paramètres de lecture pour répondre à des cas spécifiques d’animation ( _plus de détails dans la suite de l’article_).

### La magie du offset et du repeat

Pour afficher la bonne zone de la texture, on a joué sur les propriétés [offset](https://threejs.org/docs/?q=Texture%23api/en/textures/Texture.offset) et [repeat](https://threejs.org/docs/?q=Texture%23api/en/textures/Texture.repeat) de la texture. Ça nous a permis d’isoler une image précise dans notre spritesheet et de l’afficher sur notre _sprite_.

```javascript

```

## Quelques fonctionnalités

Penchons-nous sur quelques fonctionnalités intéressantes du _player_ :

### Plusieurs spritesheets

Si on souhaite regrouper toutes les images en une seule, les dimensions de la texture à gérer par le navigateur risquent d’être énormes. En regardant le [rapport webgl](https://webglreport.com/), la taille maximale d’une texture est de 16384px sur ordinateur, alors qu’elle est de 4096px sur un appareil mobile.

Dans ce cas-ci, l’animation est relativement courte avec une durée de moins de deux secondes. Imaginons une animation plus longue avec une résolution plus haute : on se retrouverait à devoir gérer une texture très lourde, ce qui pourrait poser un problème de performance sur certains appareils.

Le _player_ permet de diviser l’animation en plusieurs spritesheets. Ici, on n’en a que huit, mais cette capacité peut s’avérer fort utile sur une animation divisée en 20 spritesheets.

### FPS, loop & wait

```javascript

```

On peut évidemment faire jouer l’animation en boucle, mais aussi définir une [cadence](https://fr.wikipedia.org/wiki/Images_par_seconde) précise pour obtenir un effet plus saccadé ou plus fluide.

On a aussi l’option d’attendre entre chaque boucle d’animation, à condition que _la lecture en boucle soit activée_. La valeur est d’ailleurs mesurée en termes d’unité de cadence : si votre application tourne à 60 images par seconde, une valeur d’attente de 30 équivaut à une demi-seconde.

### Aller plus loin avec le défilement

C’est là que le _player_ prend une tout autre dimension en liant la position de lecture au défilement.

```javascript

```

Celle qui nous intéresse particulièrement est **seek**, qui permet d’arrêter l’animation sur une image précise. Le paramètre qu’elle utilise est une valeur qui se situe entre 0 (le début) et 1 (la fin). Si on synchronise cette valeur avec un ratio de défilement (la progression du défilement sur la longueur disponible), on arrive à obtenir un _scroll_ super fluide sur une vidéo.

Video originale : [https://www.youtube.com/watch?v=Ve9z_ofFTn4&ab_channel=KevinPerez](https://www.youtube.com/watch?v=Ve9z_ofFTn4&ab_channel=KevinPerez)

Nous avons aussi mis en place une possibilité d’avoir un scroll infini, que la vidéo revienne au début et qu’elle puisse être jouée en boucle en utilisant seulement le scroll.

## Les spritesheets sont vos amies

Gérer des animations 2D dans un environnement 3D est non seulement possible, mais facile à exécuter avec un _player_ de spritesheets. Cette méthode offre de nombreuses possibilités comme la liaison avec du _scroll_ pour ajouter encore plus d’interactivité ou encore la mise en place d’une couche d’effet avec un _shader_ personnalisé.

### Liens

**[Threejs](https://threejs.org/)**(v.152) : Moteur de rendu WebGL offrant de nombreuses fonctionnalités, une foule d’exemples et qui rassemble une très grosse communauté.

[**WebGL Report**](https://webglreport.com/): Rapport WebGL listant ce qui est supporté sur votre navigateur.

[**Rive**](https://rive.app/): Logiciel pour créer des animations interactives. Facile à utiliser, il offre de nombreuses fonctionnalités intéressantes.

[**Free Texture Packer**](http://free-tex-packer.com/): Logiciel de création de spritesheets.
