WebGPU Spirit Vortex
Quatorze mille esprits dérivent en champ ouvert et se regroupent en vortex dès que le curseur approche — repli canvas 2D intégré si WebGPU est absent.
Mis à jour le
Cet effet fait partie d'Effect.Labs — 840 effets vanilla, une partie gratuite, une partie premium. Atmosphère comprend 58 effets, dont 10 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Quatorze mille graines sont tirées une seule fois dans un Float32Array : deux nombres aléatoires par particule, invariants pendant toute la durée de vie de la page. L'état ambiant est calculé à chaque image depuis la graine et le temps : angle de dérive lent (a0 + t × (0,08 + r × 0,25)), rayon conservé à 92 % pour éviter les trajectoires trop excentriques. Il n'y a aucun tableau de positions à maintenir.
Quand le curseur se trouve dans la scène, ses coordonnées normalisées (mx, my en espace clip, corrigées par le rapport d'aspect) sont envoyées au nuanceur WGSL à chaque image via le tampon uniforme. Le nuanceur calcule la distance d entre la position ambiante de la particule et le curseur, puis un facteur d'attraction k = clamp(0,7 / (d + 0,5), 0, 0,85) : nul loin du curseur, fort mais jamais total à proximité. La particule est interpolée entre sa position ambiante et une position sur une spirale centrée sur le curseur — angle tangentiel atan2 + t × 1,7 − d × 2,6, rayon progressivement réduit vers un noyau de 0,06. La couleur passe du turquoise ((0,32, 0,85, 0,68)) au violet ((0,80, 0,68, 1,0)) selon k.
Au démarrage, le code suit exactement la même cascade de trois vérifications que WebGPU Particle Field (fx-0802) : présence de navigator.gpu, obtention d'un adaptateur et d'un périphérique, réponse du contexte webgpu. Chaque échec, comme toute exception, bascule sur le moteur canvas 2D qui reproduit la même logique d'attraction en JavaScript — même rendu, même interaction, moins de particules.
Accessibilité
- Sous
prefers-reduced-motion: reduce, le temps est figé à zéro : les particules restent immobiles dans leur disposition initiale. L'interaction au curseur est toujours active (le code ne la désactive pas), mais comme le temps ne progresse pas, la spirale elle-même ne tourne plus — le portail est ouvert mais figé. - Le canvas ne porte aucune information : c'est une décoration. L'étiquette de mode
[data-sws-tag]est marquéearia-hidden="true". - Le repli canvas 2D est visuellement complet : un visiteur sans WebGPU voit le même vortex interactif, avec moins de particules. La dégradation porte sur la densité, jamais sur la présence ou l'interactivité de l'effet.
- Le curseur
crosshairde la scène signale l'interactivité sans avoir recours à un texte ou un label supplémentaire. devicePixelRatioest plafonné à 2 pour préserver la fluidité sur les écrans très denses.
Compatibilité navigateur
WebGPU (navigator.gpu, nuanceur WGSL, 4 flottants uniformes) avec repli complet en canvas 2D, plus requestAnimationFrame, matchMedia, devicePixelRatio et PointerEvent. Aucune bibliothèque.
Le repli canvas 2D couvre les trois cas d'échec WebGPU : absence de navigator.gpu, adaptateur ou périphérique refusé, contexte webgpu défaillant. Sans JavaScript, le canvas reste vide : donnez une couleur de fond à .sws-scene. Sans PointerEvent, les particules flottent sans interaction (très ancien navigateur).
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec votre achat) :
<div class="sws-scene" data-sws>
<!-- Le canvas est dimensionné par le script, jamais en dur -->
<canvas class="sws-canvas" width="0" height="0"></canvas>
<!-- Étiquette de mode : le script y écrit « WebGPU actif » ou « Canvas 2D (repli) ».
Utile en développement ; retirez-la en production si elle ne sert plus. -->
<div class="sws-tag" data-sws-tag aria-hidden="true">Canvas 2D (repli)</div>
</div>
Paiement unique, sans abonnement — le code est à toi pour toujours
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
N — nombre de particules |
14000 | En WebGPU, 14 000 est confortable et 80 000 reste tenable sur une carte dédiée. En repli canvas 2D, descendez vers 4 000 : le coût y est par particule, pas par image. |
| Force du portail | 0,7 / (d + 0,5), plafonné à 0,85 |
Augmenter le numérateur (ex. 1,2) renforce l'aspiration et élargit la zone d'influence. Augmenter le dénominateur (ex. 1,0) donne un portail plus doux, qui se forme seulement quand le curseur est très proche. |
| Vitesse de dérive ambiante | 0,08 + rayon × 0,25 |
Le facteur 0,08 est la vitesse minimale au centre. Le facteur 0,25 différencie centre et périphérie (rotation lente vers rotation rapide). Réduire les deux donne un champ quasi figé, presque fantomatique. |
| Vitesse et pas de la spirale | angle t × 1,7 − d × 2,6 |
Le coefficient 1,7 règle la vitesse de rotation du portail. Le coefficient 2,6 contrôle l'enroulement des bras : plus il est élevé, plus les particules proches forment une spirale serrée. |
| Rayon de convergence | mix(d, 0,06, k) |
Le 0,06 est le rayon du noyau du portail (en coordonnées clip). Un rayon plus grand (ex. 0,15) donne un portail ouvert avec un œil visible ; un rayon plus petit (0,02) concentre quasiment toutes les particules en un point. |
| Palette | turquoise (0,32, 0,85, 0,68) → violet (0,80, 0,68, 1,0) selon k |
Les deux extrémités contrôlent la couleur ambiante (faible k) et la couleur du portail (fort k). Pour une ambiance Halloween, remplacez le turquoise par un orange doux et le violet par un rouge sang. |
Plafond de devicePixelRatio |
2 | Compromis netteté / charge. Ne montez pas au-delà de 2 : le gain visuel sur les points fins est marginal, la charge GPU augmente en carré. |
FAQ
[data-sws] trouvées dans le document. Chaque scène a ses propres graines, son propre canvas et son propre suivi de curseur : les vortex sont indépendants. Sur une page à défilement, un IntersectionObserver peut être ajouté pour suspendre les boucles hors de l'écran.pointermove reçoit aussi les événements tactiles sur mobile. Un glissement du doigt sur la scène ouvre le portail, et le relâchement (pointerleave) renvoie les particules en dérive ambiante. La position par défaut [99, 99] (hors de l'espace clip normalisé) désactive l'attraction entre les interactions.