Atmosphère✨ Premium

Circular Visualizer

32 barres CSS en cercle animées par deux oscillateurs Math.sin + bruit — pur DOM, zéro canvas, compatible AnalyserNode Web Audio.

JSRadial

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 — Page d'accueil d'une app audio — Circular Visualizer exemple 1

① Hero / Landing — Page d'accueil d'une app audio

QuandEn fond d'une hero section d'application musicale ou de podcast, quand on veut signaler en un coup d'œil que le produit manipule de l'audio.
PourquoiLe cercle animé évoque un égaliseur sans abstraire le message texte. Centré et agrandi (200 px), il capte l'attention sans dominer le CTA.
RéglagesContainer 200 × 200 px (.circular-visualizer { width: 200px; height: 200px }), 40 barres (circularBarCount = 40), gradient mauve-violet (#8b5cf6 → #c026d3).
Lecteur audio plein écran — écran « Now Playing » d'une app musicale — Circular Visualizer exemple 2

② Lecteur audio plein écran — écran « Now Playing » d'une app musicale

QuandSur l'écran « Now Playing » d'une app musicale mobile ou web, pour entourer la pochette d'album d'un halo animé qui pulse au rythme de la musique.
PourquoiLe visualiseur radial à 220 px entoure naturellement une pochette carrée de 80 px : les 40 barres forment une couronne lumineuse impossible à reproduire avec un égaliseur en barres classique. C'est le contexte où l'effet est le plus reconnaissable et le plus spectaculaire.
RéglagesContainer 220 × 220 px (.circular-visualizer { width: 220px; height: 220px }), 40 barres (circularBarCount = 40), gradient rose-violet (#ec4899 → #8b5cf6), transition height 0.03s pour un rendu nerveux.
Micro-interaction de conversion — Confirmation d'enregistrement — Circular Visualizer exemple 3

③ Micro-interaction de conversion — Confirmation d'enregistrement

QuandJuste après qu'un utilisateur a exporté ou sauvegardé un fichier audio — la fenêtre de confirmation affiche le visualiseur comme preuve que l'audio a été détecté.
PourquoiUn visualiseur qui pulse sur l'écran de succès renforce la confiance sans nécessiter un vrai playback — la simulation suffit à créer le sentiment de validation.
RéglagesContainer réduit à 80 × 80 px, 16 barres (circularBarCount = 16), gradient validation vert (#22c55e → #10b981), barres plus larges (width: 6px).

Comment ça marche

Le container .circular-visualizer est un carré de 160 × 160 px en position:relative. Le JS crée 32 .bar positionnés en position:absolute; bottom:50%; left:50% avec transform-origin: center bottom. Chaque barre reçoit translateX(-50%) rotate(i/32 × 360°) : la translation centre la barre sur son axe, la rotation la fait pointer vers l'extérieur. Le résultat est 32 rayons équidistants autour d'un centre commun.

getSimulatedAudio(32, time, 0.5) génère pour chaque barre une valeur [0–1] à partir de deux oscillateurs Math.sin à des fréquences distinctes (baseFreq + i × 0.5 et × 1.5 de cette fréquence), plus 20 % de Math.random(). La combinaison produit un signal organique où chaque barre a son propre rythme d'oscillation — sans aucune permission microphone ni API Web Audio.

À chaque frame du requestAnimationFrame, animateCircularVisualizer(time) mappe chaque valeur simulée sur une hauteur 20 + valeur × 50 px (fourchette 20–70 px) et réécrit bar.style.height et bar.style.transform. La propriété CSS transition: height 0.05s lisse les sauts discrets frame-par-frame en un mouvement fluide sans easing JS.

Aucun gestionnaire prefers-reduced-motion n'est présent : la boucle rAF tourne sans condition. Aucune destruction (cancelAnimationFrame) ni IntersectionObserver n'est prévue dans le code de base — à ajouter dans l'intégration si le composant est hors-viewport.

Accessibilité

  • prefers-reduced-motion absent : aucune détection dans le code — le rAF tourne en continu quelle que soit la préférence OS. Ajoutez vous-même if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; avant requestAnimationFrame(animate).
  • Le container .circular-visualizer n'a ni role ni aria-label dans le code de base — décoratif par défaut. Ajoutez role="img" aria-label="Visualiseur audio circulaire" dans votre intégration si l'élément porte du sens.
  • Les barres générées par JS sont de purs divs décoratifs sans texte : aucun lecteur d'écran ne les annoncera (comportement souhaité).
  • Aucune interaction clavier ni focus : l'effet est passif, pas d'événements souris ou clavier à gérer.
  • Le gradient #6366f1 → #06b6d4 sur fond #0a0a0f atteint un ratio de luminance ~4,2:1 — acceptable WCAG AA pour un élément décoratif.

Compatibilité navigateur

Pur DOM + CSS transforms + requestAnimationFrame — aucun canvas, aucune dépendance externe. Fonctionne partout où CSS 3D transforms et rAF sont disponibles.

Chrome 88+✓ Complet
Firefox 87+✓ Complet
Safari 15+✓ Complet
Edge 88+✓ Complet
Mobile iOS✓ Complet
Android Chrome✓ Complet

Si JS est désactivé, le container <code>.circular-visualizer</code> s'affiche vide (160 × 160 px, fond transparent) — aucune erreur, la page reste fonctionnelle. Si le HTML embarqué est utilisé, les 32 barres pré-rendues restent statiques au snapshot initial.

Le code

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

index.html — structure
<div class="demo-preview">
  <div class="circular-visualizer"
       id="circularVisualizer"
       role="img"
       aria-label="Visualiseur audio circulaire">
    <!-- 32 éléments .bar injectés par JS -->
  </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
.circular-visualizer { width / height } 160px Taille du container = rayon apparent du cercle. Modifiez les deux dimensions ensemble pour agrandir ou réduire l'ensemble.
.circular-visualizer .bar { background } linear-gradient(to top, #6366f1, #06b6d4) Couleurs du dégradé des barres, de la base (couleur sombre) au sommet (couleur vive). Remplacez par votre palette brand.
.circular-visualizer .bar { width } 4px Épaisseur de chaque barre en px. Augmentez à 6–8 px pour peu de barres (≤ 16), réduisez à 2–3 px pour beaucoup de barres (≥ 48).
.circular-visualizer .bar { transition } height 0.05s Délai de lissage entre deux frames. Réduisez à 0.02s pour un rendu plus nerveux, augmentez à 0.15s pour un mouvement plus liquide.
circularBarCount = 32 32 Nombre de barres dans le cercle. Entre 16 (effet large, espacé) et 64 (couronne dense). Toujours mettre à jour la largeur de barre en conséquence.
20 + data[i] * 50 dans animateCircularVisualizer min 20 px, max 70 px Hauteur minimale (20) et amplitude (50) de chaque barre en px. Augmentez l'amplitude à 80 pour un effet plus dramatique, réduisez le minimum à 10 pour un effet plus discret au silence.
getSimulatedAudio(32, time, 0.5) — 3e argument 0.5 Fréquence de base des oscillateurs. Augmentez à 1.5 pour une animation plus rapide, réduisez à 0.2 pour un mouvement lent et régulier.

FAQ

Non — tout le mouvement est simulé par getSimulatedAudio() (deux Math.sin() par barre + 20 % de bruit aléatoire). Aucune permission microphone n'est demandée. Pour brancher un vrai flux audio, remplacez l'appel à getSimulatedAudio() par une lecture de analyserNode.getByteFrequencyData(data) divisée par 255 pour normaliser entre 0 et 1.
Le code de base ne l'optimise pas. Encapsulez la boucle rAF dans un IntersectionObserver : à l'entrée dans le viewport appelez requestAnimationFrame(animate), à la sortie appelez cancelAnimationFrame(rafId). C'est la même technique que l'effet Balloon Release (fx-0837) qui inclut cet IntersectionObserver nativement.
Non — le rAF tourne sans condition dans le code de base. Pour le respecter, testez window.matchMedia('(prefers-reduced-motion: reduce)').matches avant de démarrer la boucle. Si la préférence est active, dessinez les barres une seule fois à hauteur fixe (par exemple 30 px) sans lancer de rAF.