Atmosphère✨ Premium

Galaxy Spiral

Un canvas 2D anime 400 étoiles en rotation différentielle sur 3 bras spiraux — noyau radial lumineux et persistance par alpha compositing.

JSCanvasGalaxy

Vous aurez accès à la démo interactive avec un compte gratuit.

Cet effet fait partie d'Effect.Labs — 811 effets vanilla, une partie gratuite, une partie premium. Atmosphère comprend 57 effets, dont 10 gratuits. Découvrir la catégorie →

3 exemples d'usage

Hero / Landing — Bannière spatiale pour SaaS tech — Galaxy Spiral exemple 1

① Hero / Landing — Bannière spatiale pour SaaS tech

QuandPage d'accueil d'un SaaS d'exploration de données, d'astronomie ou d'un produit à univers « espace » — fond de section hero pleine largeur.
PourquoiLa galaxie en mouvement lent crée une profondeur cinématographique sans écraser le message texte overlay — le trail alpha compositing génère un fond dynamique qui respire.
RéglagesRayon max réduit à 0,35 (Math.min(t.w,t.h)*0.35) pour concentrer la spirale au centre ; palette réduite à 3 couleurs brand (["#a78bfa","#60a5fa","#fff"]) ; trail alpha à 0,05 pour des traînées plus longues.
Planétarium interactif — Scène principale d'une app d'astronomie — Galaxy Spiral exemple 2

② Planétarium interactif — Scène principale d'une app d'astronomie

QuandApplication web d'astronomie ou planétarium en ligne — la galaxie occupe toute la surface principale, avec une interface minimale en overlay pour la navigation et les données.
PourquoiLes 3 bras spiraux, la rotation différentielle et le trail alpha compositing sont pleinement lisibles sur grande surface (≥ 400 px) — l'effet est la scène elle-même, pas un accessoire de carte.
RéglagesRayon max à 0,42 (valeur par défaut) pour que les bras occupent tout l'espace disponible ; palette complète 5 couleurs pour un rendu astrophysique réaliste ; trail alpha abaissé à 0,06 pour des traînées plus longues et cinématographiques (rgba(10,10,15,0.06)).
Micro-interaction de conversion — Écran de confirmation d'inscription — Galaxy Spiral exemple 3

③ Micro-interaction de conversion — Écran de confirmation d'inscription

QuandL'utilisateur vient de créer un compte, valider un paiement ou atteindre son premier jalon clé — l'écran de succès s'affiche en plein écran.
PourquoiLa galaxie en arrière-plan évoque un univers de possibilités qui s'ouvre — renfort émotionnel de la décision d'achat au moment le plus impactant du tunnel.
RéglagesCanvas plein écran (100 vw/vh) ; palette réduite aux tons violets et bleus (["#a78bfa","#60a5fa","#fff"]) pour un ressenti premium ; twist diviseur abaissé à 50 (dist/50) pour des bras plus serrés et plus spectaculaires.

Comment ça marche

Au chargement, 400 étoiles sont placées selon une formule spirale. Chaque étoile appartient à l'un des 3 bras (index % 3) ; son angle initial vaut bras/3 × 2π + dist/80. Le terme dist/80 est le twist radial : plus l'étoile est éloignée du centre, plus elle s'enroule dans son bras. Un jitter de ±0,5 rad la disperse naturellement autour de l'axe du bras. La distance au centre est tirée aléatoirement jusqu'à Math.min(w,h) × 0,42.

La boucle RAF met à jour angle += speed à chaque frame. La vitesse décroît avec la distance : 3×10⁻⁴ + 0,001 × (1 − r/r_max) — c'est la rotation différentielle caractéristique des galaxies réelles (le noyau tourne plus vite que les bras extérieurs). Le canvas n'est pas effacé entre frames : un fillRect semi-transparent avec alpha 0,08 recouvre progressivement les positions passées, produisant un trail de persistance par alpha compositing — il faut ~12 frames (~200 ms à 60 fps) pour qu'une position s'efface complètement.

Un dégradé radial est redessiné à chaque frame sur le noyau central (rayon fixe 30 px) : il va de rgba(200,180,255,0.1) vers transparent, simulant l'éclat d'un bulbe galactique. Chaque étoile est un arc() de 0,5–2 px peint dans l'une des 5 couleurs hardcodées ["#fff","#a78bfa","#ec4899","#fbbf24","#60a5fa"], avec une opacité individuelle de 0,3–0,8.

L'effet s'initialise sur l'id="psGalaxy" via getElementByIdune seule instance par page dans le code source. Aucun IntersectionObserver ne coupe le RAF hors viewport (boucle en continu). Aucune API publique n'est exposée : les paramètres sont des constantes JS à modifier directement dans le source.

Accessibilité

  • prefers-reduced-motion non géré : l'animation tourne inconditionnellement, sans fallback statique. Côté intégration, wrappez l'init dans if (!matchMedia('(prefers-reduced-motion:reduce)').matches) {…} et masquez le canvas via @media (prefers-reduced-motion:reduce){.ps-canvas{display:none}}.
  • Le <canvas> ne porte pas aria-hidden="true" dans le code source — ajoutez-le pour que les lecteurs d'écran ignorent l'élément graphique.
  • Aucun role="img" ni aria-label sur le conteneur — à renseigner selon le contexte (ex. aria-label="Galaxie spirale animée — décoration").
  • L'effet est purement décoratif et non interactif : aucun gestionnaire clavier, aucune cible de focus, aucun événement pointeur.
  • Les étoiles colorées sur fond #0a0a0f offrent un contraste visuel élevé (décoration seule — aucun texte à risque de contraste n'est rendu dans le canvas).

Compatibilité navigateur

Nécessite Canvas 2D Context et requestAnimationFrame — disponibles dans tous les navigateurs modernes. Le CSS utilise :has() pour styler le conteneur (Chrome 105+, Firefox 121+, Safari 15.4+) ; l'absence de ce sélecteur n'affecte que le style de fallback du wrap, pas l'animation.

Chrome 105+✓ Complet
Firefox 121+✓ Complet
Safari 15.4+✓ Complet
Edge 105+✓ Complet
iOS Safari 15.4+✓ Complet
Android Chrome✓ Complet

Si <code>canvas</code> n'est pas supporté, le <code>.ps-canvas-wrap</code> s'affiche vide sur fond sombre. Le guard <code>if (!t) return</code> en tête d'IIFE empêche toute erreur JS.

Le code

Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :

index.html — structure
<div class="demo-preview">
  <div class="ps-canvas-wrap">
    <!-- ⚠ id="psGalaxy" est hardcodé dans le JS : une seule instance par page sans adaptation -->
    <canvas class="ps-canvas" id="psGalaxy" width="392" height="280"
            aria-hidden="true"></canvas>
  </div>
</div>
🔒 Débloquer le code complet — à partir de 2,99 € le 1er mois

HTML + CSS + JS complet, prêt à coller — avec des centaines d'effets premium.

Personnaliser

Options passées à l'API ou attributs data-* :

Option / propriétéDéfautEffet
l (palette couleurs) ["#fff","#a78bfa","#ec4899","#fbbf24","#60a5fa"] Tableau des couleurs des étoiles (ligne const l=[…]). 3 couleurs pour un rendu épuré, 7+ pour un look festif. Chaque couleur est convertie manuellement en RGB dans la boucle de dessin — si vous ajoutez une couleur, ajoutez aussi son entrée dans le bloc if/else de conversion.
400 (nombre d'étoiles) 400 Taille de la boucle for(let a=0;a<400;a++). Réduisez à 150–200 pour une intégration légère sur petite surface ou mobile faible puissance.
a % 3 (bras spiraux) 3 Le modulo définit le nombre de bras. Changez en a%2 pour une galaxie barrée, a%5 pour une spirale très dense. Mettez à jour la formule d'angle en conséquence : n/3n/N.
80 (twist radial) 80 Diviseur dans dist/80. Abaissez à 40 pour des bras très enroulés et compacts, augmentez à 150 pour une spirale presque droite.
0.08 (trail alpha) 0.08 Alpha du fillRect de persistance (rgba(10,10,15,0.08)). Réduisez à 0,03 pour des traînées longues et fantasmagoriques, augmentez à 0,25 pour un rendu sec sans trail visible.
0.42 (rayon max) 0.42 Facteur appliqué à Math.min(w,h) pour la distance maximale des étoiles. 0,42 = spirale dans 84 % du petit côté. Réduisez à 0,3 pour concentrer, augmentez à 0,5 pour étaler jusqu'aux bords.
30 (rayon noyau) 30 px Rayon du dégradé radial central (createRadialGradient(cx,cy,0,cx,cy,30)). Augmentez à 60–80 pour un noyau très lumineux de type quasar ; réduisez à 10 pour un point central discret.
1.5*Math.random()+.5 (taille étoiles) 0,5–2 px Plage de rayon des étoiles. Changez en 2.5*Math.random()+1 pour des étoiles plus visibles sur grand écran, ou Math.random()+0.3 pour des points minuscules et plus réalistes.

FAQ

Le canvas n'est pas effacé entre frames. Un fillRect(0,0,w,h) avec fillStyle="rgba(10,10,15,0.08)" recouvre progressivement les positions précédentes — technique dite alpha compositing trail. À alpha 0,08, une position met ~12 frames (~200 ms à 60 fps) avant de disparaître. Augmentez cet alpha pour réduire les traînées, diminuez-le pour les allonger.
Modifiez la ligne const n = a % 3 en const n = a % 4 (ou % 5). Mettez à jour la formule d'angle : n / 3 * Math.PI * 2 devient n / 4 * Math.PI * 2. Ajustez aussi le twist en augmentant le diviseur (ex. dist/120) pour éviter que les bras supplémentaires se chevauchent trop près du centre.
Non dans l'état actuel — l'IIFE lance le RAF sans vérifier prefers-reduced-motion. Pour corriger côté intégration : wrappez l'initialisation dans if (!window.matchMedia('(prefers-reduced-motion:reduce)').matches) { /* init */ }, et masquez le canvas via @media (prefers-reduced-motion:reduce){.ps-canvas{display:none}} en CSS.