Circular Visualizer
32 barres CSS en cercle animées par deux oscillateurs Math.sin + bruit — pur DOM, zéro canvas, compatible AnalyserNode Web Audio.
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



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;avantrequestAnimationFrame(animate). - Le container
.circular-visualizern'a niroleniaria-labeldans le code de base — décoratif par défaut. Ajoutezrole="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 → #06b6d4sur fond#0a0a0fatteint 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.
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) :
<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>
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éfaut | Effet |
|---|---|---|
| .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
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.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.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.