Communitygithub.com

shubham001312/scroll-motion-graphics

Utilisez cette compétence pour créer ou corriger une section de motion-graphique pilotée par le défilement sur une page web, comme un film canvas défilé par la position de scroll, une scène sticky de type « scrollytelling », des chapitres liés au défilement avec légendes, ou un tambour d’histoire 3D ou carrousel contrôlé par le scroll, le glisser et les touches fléchées. À utiliser également lorsqu’une animation de défilement existante saccade, détourne la molette, dessine sous son texte, ne se joue que dans un sens, consomme du CPU au repos, ou ignore prefers-reduced-motion. Ne convient pas aux simples apparitions au défilement, aux vidéos en lecture automatique ni aux scènes WebGL.

Qu'est-ce que scroll-motion-graphics ?

Cette compétence définit une méthode complète pour construire des animations 2D pilotées par le défilement sur le Web, où la position de défilement est la seule horloge temporelle. Elle repose sur un système de « bobines » (reels) qui sont des fonctions pures `draw(ctx, t, env)`, sans état ni horloge, garantissant une lecture fluide dans les deux sens. La technique utilise un conteneur `position: sticky` et une piste haute (`N×vh`) pour créer une scène épinglée, sans jamais capturer la molette ni bloquer le défilement. Les légendes sont en DOM réel, positionnées dans des zones de sécurité, et le canvas est redimensionné avec un DPR limité à 2 pour les performances. La compétence prend en charge le mode sombre, `prefers-reduced-motion`, l’arrêt du rendu au repos (via IntersectionObserver), et s’adapte de 360 à 1920 px de large. Elle inclut des références détaillées pour le moteur de défilement, le dessin, la mise en page, la grammaire de mouvement, les performances et l’accessibilité, ainsi qu’une démo complète et un wrapper React.

Compatible avec✓Claude Code~Codex CLI✓Cursor✓OpenCode
npx skills add https://github.com/shubham001312/imutechz-skills/tree/HEAD/skills/scroll-motion-graphics

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Motion graphiques de défilement

Une timeline canvas pilotée par la position de défilement : une scène épinglée, des bobines qui sont des fonctions pures de la progression, et des légendes que le dessin n’a jamais le droit de toucher. Cette méthode anime le tambour d’histoire de la page d’accueil d’ImuTechz, le tambour R&D et le film du parcours du fondateur. Elle alimente également la démo à cinq bobines dans assets/demo.html.

Toute la technique tient en une phrase. La position de défilement est la seule horloge : associez-la à p ∈ [0, 1] et faites en sorte que chaque pixel, légende et rotation soit une fonction de p.

À quoi ressemble un bon résultat

  • Ça défile comme une vidéo. Faites défiler vers l’avant et le film se joue. Revenez en arrière et il rembobine, image par image. S’arrêter à mi-chemin laisse une image qui a du sens.
  • La page n’est jamais détournée. La molette, le trackpad, le tactile et les touches déplacent la page exactement comme partout ailleurs. La section est simplement haute.
  • Les mots sont toujours lisibles. Les légendes sont du vrai texte DOM sur une carte. Le dessin se dispose dans l’espace laissé par les légendes, et le canvas est découpé autour d’elles comme filet de sécurité.
  • C’est un contrôle, pas seulement un spectacle. Les faces d’un tambour d’histoire sont des liens. Son rail, ses boutons fléchés, les touches fléchées et le glissement cherchent en faisant défiler la page, de sorte que le défilement et le tambour ne peuvent jamais diverger.
  • Une page au repos ne coûte rien. Aucun requestAnimationFrame ne s’exécute une fois que p s’est stabilisé ou après que la section a quitté la fenêtre.
  • Le mouvement réduit est respecté. Pas de lissage, pas de rotation intermédiaire du tambour et aucune animation d’entrée des légendes. Tout le contenu est toujours présent.
  • Ça tient de 360 à 1920 px de large, en clair et en sombre, à DPR 1 et 2.

Règles strictes

  1. p vient de la position de défilement, jamais d’une horloge. N’utilisez pas performance.now(), Date, d’animations CSS ou setInterval à l’intérieur d’une bobine. Le lissage (un lerp vers la cible p) est autorisé car il converge vers la même image.
  2. Une bobine est une fonction pure draw(ctx, t, env). Elle ne conserve aucun état entre les images et n’appelle jamais Math.random() ; utilisez un hash(i) seedé à la place. Le même (t, env) doit peindre les mêmes pixels.
  3. Épinglez avec CSS, pas JS. Utilisez une piste haute (position: relative; height: N×vh) contenant une scène position: sticky; top: 0; height: 100svh. Ne mettez jamais position: fixed sur la scène, ne verrouillez jamais le body, et ne mettez jamais overflow: hidden|auto|clip sur un ancêtre de la piste.
  4. Ne capturez jamais l’entrée. N’utilisez pas preventDefault sur la molette ou le tactile, pas de overflow: hidden sur html ou body, et pas d’accrochage au défilement sur la piste. Seul un tambour focalisé peut gérer les touches fléchées, et il le fait en faisant défiler la page.
  5. Cherchez en défilant. Chaque bouton, élément du rail, touche et ancre modifie window.scrollY. Ne définissez jamais p ou une rotation directement. Utilisez behavior: "instant" pour les sauts programmatiques qui ne doivent pas s’animer, car "auto" obéit au CSS scroll-behavior: smooth de la page.
  6. Le texte vit dans le DOM. Les légendes, titres et liens sont du HTML. Le texte du canvas est limité aux étiquettes décoratives comme les années, les repères d’axe et les noms d’étapes.
  7. Mesurez les légendes à chaque image et gardez le dessin à l’écart. Chaque légende et élément HUD est une zone d’exclusion (data-keep). Les bobines se disposent à l’intérieur de env.free, et le moteur découpe les zones d’exclusion avec un clip pair-impair.
  8. N’affichez jamais deux légendes à la fois. Les fenêtres de légende se trouvent à l’intérieur de leur bobine avec un espace à chaque limite, et les bobines font un fondu croisé dans cet espace.
  9. La boucle s’arrête au repos. Démarrez rAF au défilement ou au redimensionnement uniquement lorsque la section est proche de la fenêtre (IntersectionObserver), et arrêtez-la lorsque p est égal à la cible.
  10. Le canvas est dimensionné à la scène à min(devicePixelRatio, 2). Appelez setTransform(dpr, …) une fois par image et effacez-le à chaque image.
  11. Les couleurs proviennent des propriétés personnalisées CSS. Ne codez pas en dur une palette mode clair dans une bobine. Relisez la palette lors du changement de prefers-color-scheme.
  12. Respectez prefers-reduced-motion: reduce. N’utilisez pas de lissage, faites en sorte que le tambour s’arrête face à face et désactivez les animations d’entrée des légendes. Les images suivent toujours le défilement, car c’est l’utilisateur qui les contrôle.

Ordre de construction

Faites-le dans cet ordre. Chaque étape est testable avant la suivante.

  1. D’abord le contenu. Écrivez les chapitres : un accroche, un titre, une ou deux phrases et un lien optionnel pour chacun. Choisissez le nombre de bobines (3 à 7) et donnez à chacune environ 80 à 100 svh de défilement.
  2. Piste et scène. Ajoutez la section haute avec une scène sticky à 100svh à l’intérieur, et vérifiez qu’elle s’épingle sans aucun JS (voir layout-and-captions).
  3. Le moteur de défilement. Câblez ScrollMotion.scrub ou film (voir engine) et loggez p. Vérifiez qu’il lit 0 au début de l’épingle et 1 à la fin, et qu’il se déplace dans les deux sens.
  4. Légendes et HUD dans le DOM. Placez-les par point de rupture, marquez-les data-keep, et laissez le moteur piloter leur opacité à partir de p.
  5. Bobines, une par une. Écrivez draw(ctx, t, env) à l’intérieur de env.free (voir drawing), et défilez-la dans les deux sens avant d’écrire la suivante.
  6. Grammaire de mouvement. Ajoutez les enveloppes d’entrée, de maintien et de sortie, les décalages, les temps d’arrêt et les fondus croisés (voir motion-grammar).
  7. Interactivité, s’il s’agit d’un tambour. Ajoutez les liens des faces, le rail, les boutons précédent et suivant, les touches et le glissement, tous cherchant par défilement.
  8. Passage performance et accessibilité. Couvrez la boucle au repos, le DPR, le mouvement réduit, l’ordre de focus, le texte du lecteur d’écran et le mode sombre (voir performance-and-a11y).
  9. Vérifiez à 360, 390, 414, 768, 1024, 1280, 1440 et 1920 avec le script sans tête (voir verification). Ne considérez pas la tâche comme terminée tant que tous les tests ne passent pas.

Listes de décision

Film canvas ou transformations DOM/CSS ?

  • Beaucoup de petites pièces mobiles, lignes à dessiner, particules ou graphiques → film canvas (ScrollMotion.film).
  • Une poignée de cartes, d’images ou de panneaux de texte → transformations DOM pilotées par scrub (le tambour en est un).
  • Maillages 3D réels ou shaders → cette compétence ne suffit pas. Utilisez WebGL, mais respectez les règles 1 à 5 et 9 à 12.

Mode épingle ou vue ?

  • La section doit retenir l’écran pendant que son histoire se joue → mode: "pin" (piste haute et scène sticky).
  • L’effet suit le contenu pendant qu’il défile, comme pour les marquees ou le parallaxe → mode: "view", sans épingle.

Quelle hauteur pour la piste ?

  • Utilisez n × 80–100svh + 100svh pour un film et n × 70vh + 100vh pour un tambour. Si un testeur dit que ça va « trop vite », augmentez la hauteur. Ne ralentissez jamais en capturant la molette.

Où placer les légendes ?

  • Desktop (≥ 760 px) : à côté du dessin (carte gauche ou droite) ou comme une large carte en bas. Téléphones : toujours une feuille en bas, avec le dessin au-dessus.
  • Avec un en-tête de site fixe, définissez --sm-nav-h pour que le HUD et le tambour le dégagent.

Faut-il le tambour ?

  • Utilisez le tambour lorsque les chapitres sont des choses que l’utilisateur peut vouloir atteindre (pages, produits, sections). Sinon, utilisez le film seul.

Modes de défaillance et correctifs

SymptômeCauseCorrectif
La scène défile au lieu de s’épinglerUn ancêtre a overflow: hidden/auto/clip, ou la scène n’a pas de topSupprimez le débordement (utilisez overflow-x: clip sur le body si nécessaire) et définissez top: 0
L’animation ne se joue que dans un sens, ou saute en remontantÉtat accumulé entre les images, ou une horloge ou Math.random dans une bobineFaites de la bobine une fonction pure de t ; utilisez hash(i) pour l’aléatoire
Le dessin passe sous la légendeBobine disposée sur toute la scèneDisposez dans env.free ; gardez data-keep sur la légende ; laissez le moteur découper
Boîte de légende mesurée au mauvais endroit en milieu de fonduUtilisation de getBoundingClientRect (inclut la transformation)Mesurez les boîtes de mise en page (offsetLeft/Top/Width/Height, voir boxIn)
Deux légendes se chevauchent à une limiteLes fenêtres de légende se touchentFondu des légendes à 1 − cross et apparition à cross ; les bobines font un fondu croisé dans l’espace
Les ventilateurs tournent sur une page au reposLa boucle rAF ne s’arrête jamaisArrêtez quand cur === target ; verrouillez avec IntersectionObserver
Canvas flou sur les téléphones / lent sur 4KCanvas à la taille CSS, ou DPR non plafonnéUtilisez width = W × min(dpr, 2) et setTransform(dpr, 0, 0, dpr, 0, 0)
Le tambour et la page divergent après avoir cliqué sur le railLe contrôle a défini la rotation directementChaque contrôle appelle scrollToProgress ; la rotation ne vient jamais que de p
Le glissement saccade, puis revient en arrièreLa page a scroll-behavior: smooth, donc scrollTo(x, y) s’animeUtilisez scrollTo({ top, behavior: "instant" }) pendant le glissement
Cliquer sur une face après un glissement ouvre son lienLe clic qui termine un glissement se déclencheAvalez un clic en phase de capture après un glissement qui a bougé de plus de 4 px
Saut de 100vh sur mobile lorsque la barre d’URL se cachevh sur la scèneUtilisez 100svh pour la scène ; calculez p avec la propre hauteur de la scène
Le mode sombre montre un dessin en mode clairCouleurs codées en durLisez les jetons --sm-* via readPalette ; relisez lors du changement de schéma
Les faces arrière du tambour apparaissentAbsence de backface-visibility: hiddenDéfinissez-le, avec le préfixe -webkit-, sur chaque face
Vignettes des faces du tambour dessinées à la mauvaise tailleUtilisation du rectangle projeté d’une face transformée en 3DDimensionnez par clientWidth/clientHeight

Fichiers

  • references/engine.md : p, la boucle de défilement, film(), la recherche, le hook React.
  • references/drawing.md : le contrat de bobine, la configuration du canvas, les routes, les pop-ins, les particules et les palettes.
  • references/layout-and-captions.md : CSS de la piste et de la scène, zones d’exclusion, rectangle libre, le clip, la disposition du tambour.
  • references/motion-grammar.md : enveloppes, décalages, temps d’arrêt, fondus croisés, rythme et assouplissements.
  • references/performance-and-a11y.md : la boucle au repos, le coût de mise en page, le mouvement réduit, le clavier, le focus et les lecteurs d’écran.
  • references/verification.md : les huit largeurs, le script Brave/Chrome sans tête et la validation manuelle.
  • assets/demo.html : autonome, zéro dépendance, double-clic pour lancer. Cinq bobines et le tambour d’histoire.
  • assets/scroll-motion.js : le moteur (scrub, film, drum, scrollToProgress et les helpers), UMD.
  • assets/reels.js : cinq bobines d’exemple (orbite, chemin, pile, vague, fermeture) et still() pour les vignettes.
  • assets/scroll-motion.css : styles du film et du tambour, jetons clair et sombre.
  • assets/ScrollFilm.jsx : le wrapper React pour le film, plus le hook useScrub.
  • assets/StoryDrum.jsx : le tambour d’histoire React, plus un DrumPreview à défilement automatique.
  • assets/preview-orbit.jpg, assets/preview-path.jpg, assets/preview-close.jpg : captures de la démo à 1440 × 900.

Commencez par la démo : ouvrez-la, regardez la source et remplacez le contenu. Le câblage en bas du fichier fait environ 60 lignes.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Skills associés