Avec

Outils

Quelques mois après mon arrivée chez Ensemble ↗, dans un but d’entrainement, on me propose l’exercice de choisir une création en motion design parmi une série présélectionnée, et de la convertir en un site fonctionnel.

Sélection

J’ai choisi ce motion par Savee :

Ce motion leur sert à présenter leur curation graphique de la semaine.

Technique

Stack

J’ai utilisé un système de composants React, alimentés via un studio Sanity intégré, stylisés uniquement avec TailwindCSS et des propriétés CSS inline générées via les composants JSX. Le scroll de l’utilisateur entraîne la rotation de la figure.

CSS

Des rectangles rouges légèrement transparents, tous collés par un côté forment une sorte de moulin à eau, ici en perspective dans l’obscurité.
Le résultat si on remplace les images par des rectangles.

Pour obtenir cet effet, il suffit de calculer les rotation et translations qui seront attribuées à chaque élément.

// Angle séparant deux images, à partir du nombre d’items
const angleStep = 360 / projects.length;

return (
// ...
{
  projects.map((project: Project, index) => {
    // Angle de chaque image, en prenant en compte le scroll
    const angle = angleStep * index + (virtualScroll / 6 / radius) * 360;

    // Translations de chaque image pour qu’elle soit correctement positionnée
    const z = radius * Math.cos((angle * Math.PI) / 180);
    const x = -radius * Math.sin((angle * Math.PI) / 180);

    // Z-index de chaque image
    const zIndex = Math.round((-x / radius) * 100);

    return (
      <div
        key={project._id}
        className="absolute left-0 top-0 h-full w-full overflow-hidden rounded-s-md"
        style={{
          transform: `
                    rotateY(${angle}deg)
                    translateX(${x - radius}px)
                    translateZ(${z}px)
                  `,
          zIndex: zIndex
        }}
      >
        {/* Un dégradé pour l’ombre */}
        <div className="absolute inset-0 bg-gradient-to-l from-black opacity-80"></div>
        {/* Une image */}
        <Image
          src={project.image}
          alt={project.name}
          width={750}
          height={750}
          className="h-full object-cover"
        />
      </div>
    )}
  )}
)

Résultat

La même chose mais avec des images au lieu des rectangles
Et voilà avec des images !