Atmosphere✨ Premium

Circular Visualizer

32 CSS bars in a circle animated by two Math.sin oscillators plus noise — pure DOM, zero canvas, plug-in ready for a Web Audio AnalyserNode.

JSRadial

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Atmosphere has 57 effects, including 10 free. Explore the category →

3 usage examples

Hero / Landing — Audio app homepage — Circular Visualizer example 1

① Hero / Landing — Audio app homepage

WhenAs the background of a music or podcast app hero section, to immediately signal that the product handles audio.
WhyThe animated circle evokes an equalizer without obscuring the text message. Centered and enlarged (200 px), it draws attention without overpowering the CTA.
SettingsContainer 200 × 200 px (.circular-visualizer { width: 200px; height: 200px }), 40 bars (circularBarCount = 40), mauve-violet gradient (#8b5cf6 → #c026d3).
Full-screen audio player — Now Playing screen in a music app — Circular Visualizer example 2

② Full-screen audio player — Now Playing screen in a music app

WhenOn the Now Playing screen of a mobile or web music app, to surround the album art with an animated halo that pulses with the music.
WhyThe 220 px radial visualizer naturally wraps a 80 px album art square: the 40 bars form a glowing crown that no classic bar equalizer can match. This is the context where the effect is most recognisable and most spectacular.
SettingsContainer 220 × 220 px (.circular-visualizer { width: 220px; height: 220px }), 40 bars (circularBarCount = 40), pink-purple gradient (#ec4899 → #8b5cf6), transition height 0.03s for a snappier feel.
Conversion micro-interaction — Recording confirmation — Circular Visualizer example 3

③ Conversion micro-interaction — Recording confirmation

WhenRight after a user exports or saves an audio file — the confirmation screen displays the visualizer as proof that audio was detected.
WhyA pulsing visualizer on the success screen builds trust without requiring real playback — the simulation alone creates a sense of validation.
SettingsContainer reduced to 80 × 80 px, 16 bars (circularBarCount = 16), validation green gradient (#22c55e → #10b981), wider bars (width: 6px).

How it works

The .circular-visualizer container is a 160 × 160 px square in position:relative. The JS creates 32 .bar elements positioned position:absolute; bottom:50%; left:50% with transform-origin: center bottom. Each bar gets translateX(-50%) rotate(i/32 × 360°): the translation centers the bar on its axis, the rotation points it outward. The result is 32 evenly-spaced radii around a shared center.

getSimulatedAudio(32, time, 0.5) generates a [0–1] value per bar using two Math.sin oscillators at distinct frequencies (baseFreq + i × 0.5 and × 1.5 of that), plus 20% Math.random(). The combination produces an organic signal where each bar has its own oscillation rhythm — no microphone permission or Web Audio API required.

On each requestAnimationFrame tick, animateCircularVisualizer(time) maps each simulated value to a height of 20 + value × 50 px (range 20–70 px) and rewrites bar.style.height and bar.style.transform. The CSS transition: height 0.05s smooths discrete per-frame jumps into fluid motion without any JS easing.

No prefers-reduced-motion handler is present: the rAF loop runs unconditionally. No cancelAnimationFrame or IntersectionObserver is built in — add these in your integration if the component is off-viewport.

Accessibility

  • prefers-reduced-motion not handled: no detection in the code — the rAF runs continuously regardless of OS preference. Add if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; before requestAnimationFrame(animate).
  • The .circular-visualizer container has no role or aria-label in the base code — decorative by default. Add role="img" aria-label="Circular audio visualizer" in your integration if the element is meaningful.
  • Bars are pure decorative divs with no text content: screen readers will not announce them (intended behavior).
  • No keyboard interaction or focus: the effect is passive, no mouse or keyboard events are managed.
  • The gradient #6366f1 → #06b6d4 on a #0a0a0f background achieves a luminance ratio of ~4.2:1 — acceptable WCAG AA for a decorative element.

Browser compatibility

Pure DOM + CSS transforms + requestAnimationFrame — no canvas, no external dependency. Works anywhere CSS 3D transforms and rAF are available.

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

If JS is disabled, the <code>.circular-visualizer</code> container renders empty (160 × 160 px, transparent background) — no errors, the page stays functional. If the embedded HTML is used, the 32 pre-rendered bars stay static at their initial snapshot heights.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="demo-preview">
  <div class="circular-visualizer"
       id="circularVisualizer"
       role="img"
       aria-label="Circular audio visualizer">
    <!-- 32 .bar elements injected by JS -->
  </div>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
.circular-visualizer { width / height } 160px Container size = apparent circle radius. Change both dimensions together to scale up or down.
.circular-visualizer .bar { background } linear-gradient(to top, #6366f1, #06b6d4) Bar gradient colors, from base (dark color) to tip (bright color). Replace with your brand palette.
.circular-visualizer .bar { width } 4px Bar thickness in px. Increase to 6–8 px for few bars (≤ 16), reduce to 2–3 px for many bars (≥ 48).
.circular-visualizer .bar { transition } height 0.05s Smoothing delay between frames. Reduce to 0.02s for a snappier feel, increase to 0.15s for a more liquid motion.
circularBarCount = 32 32 Number of bars in the circle. Between 16 (wide, spaced) and 64 (dense crown). Always update bar width accordingly.
20 + data[i] * 50 in animateCircularVisualizer min 20 px, max 70 px Minimum height (20) and amplitude (50) per bar in px. Increase amplitude to 80 for a more dramatic effect, lower the minimum to 10 for a subtler idle state.
getSimulatedAudio(32, time, 0.5) — 3rd argument 0.5 Base oscillator frequency. Increase to 1.5 for faster animation, reduce to 0.2 for slow, steady motion.

FAQ

No — all motion is simulated by getSimulatedAudio() (two Math.sin() per bar plus 20% random noise). No microphone permission is requested. To connect a real audio stream, replace the getSimulatedAudio() call with a read from analyserNode.getByteFrequencyData(data) divided by 255 to normalise between 0 and 1.
The base code does not optimise for this. Wrap the rAF loop in an IntersectionObserver: call requestAnimationFrame(animate) on viewport entry and cancelAnimationFrame(rafId) on exit. The Balloon Release effect (fx-0837) includes this IntersectionObserver natively as a reference.
No — the rAF loop runs unconditionally in the base code. To respect the preference, test window.matchMedia('(prefers-reduced-motion: reduce)').matches before starting the loop. If the preference is active, render the bars once at a fixed height (e.g. 30 px) without launching a rAF.