Atmosphere✨ Premium

Spectrum Gradient

Sixteen DOM bars with a rotating HSL gradient — violet to magenta, heights driven by two sinusoids plus noise, no canvas, no library.

JSColorful

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 streaming visualizer — Spectrum Gradient example 1

① Hero / Landing — Audio streaming visualizer

WhenFull-width on the homepage of a music streaming service or audio editing tool, before the user triggers playback.
WhyThe continuously animating spectrum simulates a live audio signal on arrival — the user perceives the product as active without any interaction, strengthening the initial hook.
Settings32 bars (spectrumBarCount = 32), container height: 200px, base hue 180° (cyan), amplitude 1.5× (10 + data[i] * 150), gap: 1px.
Stream overlay — Full-width spectrum at the bottom — Spectrum Gradient example 2

② Stream overlay — Full-width spectrum at the bottom

WhenAs a bottom strip in an OBS/Twitch overlay or a full-screen music player, the bars span the full scene width during a live broadcast.
WhyWith 32 bars at 180 px height, the effect unfolds its full violet-to-magenta palette: the graphic power is immediately visible, not reduced to a corner of the interface.
Settings32 bars (spectrumBarCount = 32), height: 180px, width: 14px on .spectrum-gradient .bar, amplitude 160 px (10 + data[i] * 150), gap: 2px, base hue 270° (violet–pink).
Conversion micro-interaction — Premium pricing section — Spectrum Gradient example 3

③ Conversion micro-interaction — Premium pricing section

WhenBehind the premium offer card or upgrade modal, to visually distinguish the paid tier from the static free tier.
WhyThe low-opacity spectrum (0.35) creates subliminal visual richness associated with the premium offer without obscuring the pricing text or drawing the eye away from the CTA.
Settings24 bars, base hue 0° (red-orange, urgency/value), opacity: 0.35 on the container, reduced amplitude 40 px (10 + data[i] * 30).

How it works

Sixteen <div class="bar"> elements are injected into the .spectrum-gradient container by the init script. On each requestAnimationFrame tick, every bar receives a freshly computed linear-gradient(to top, hsl(h, 80%, 50%), hsl(h+30, 80%, 60%)) via .style.background, and a new height between 10 and 110 px via .style.height. The CSS transition height 0.05s smooths inter-frame jumps without burdening the loop.

The hue h for each bar follows (i / 16) × 60 + 240 + sin(t × 0.002) × 30. The linear term spreads the bars across 60° of the color wheel (violet 240° → magenta 300°). The sinusoidal term oscillates the entire palette by ±30° over ~3 seconds, making the colors appear to breathe together.

Heights come from getSimulatedAudio(n, time): for bar at index i, the local frequency is 1 + i × 0.5 and the value is |sin(t × freq × 0.002) × 0.5 + sin(t × freq × 0.003 + i) × 0.3 + rand × 0.2|, clamped to [0, 1]. Two sinusoidal oscillators at frequencies proportional to the bar index create staggered rise/fall patterns; the 20% random noise component reproduces the irregularity of a real audio signal.

Accessibility

  • prefers-reduced-motion not implemented: the code does not detect prefers-reduced-motion — the RAF runs continuously regardless of OS settings. Must be added manually (see FAQ).
  • The .spectrum-gradient container carries neither aria-hidden nor role="img" nor aria-label — the DOM bars are reachable by screen readers but carry no semantic description.
  • The effect is purely decorative: no interactive element is attached, and the keyboard tab order is unaffected.
  • The height 0.05s transition stays active regardless of user preferences — animated height changes cannot be disabled through OS settings.
  • If the effect is embedded in a semantic context, add aria-hidden="true" to the container or a descriptive aria-label on the parent element.

Browser compatibility

Requires CSS flexbox, linear-gradient, and requestAnimationFrame — supported in all modern browsers. Zero canvas, zero external dependencies.

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

If JS is disabled, the 16 bars stay at their initial 10 px height with no gradient — the container renders empty but error-free.

The code

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

index.html — structure
<div class="spectrum-gradient" id="spectrumGradient">
  <!-- .bar divs are injected by the JS at init -->
</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
spectrumBarCount = 16 16 Number of bars (JS constant). 8 = airy, 32 = dense. Also adjust the CSS gap above 24 bars.
.spectrum-gradient { height } 120px Container max height (CSS). 200 px for a full-height hero, 60–80 px for a compact widget.
.spectrum-gradient .bar { width } 12px Width of each bar (CSS). 8 px = tight spectrum, 16–20 px = strong graphic effect.
.bars-3d, .spectrum-gradient { gap } 3px Gap between bars (CSS, shared rule with .bars-3d). 1 px = dense, 6 px = airy.
hue offset +240 240 HSL starting hue in animateSpectrumGradient. 0 = red, 120 = green, 180 = cyan, 240 = violet (default).
hue range ×60 60 Hue range across the 16 bars (degrees). 30 = narrow monochromatic palette, 120 = wide rainbow gradient.
amplitude ×100 100 Height factor in 10 + data[i] * 100. 40–50 = subtle overlay, 150 = dramatic full-height.
rotation speed 0.002 0.002 HSL palette oscillation speed (Math.sin(time * 0.002)). 0.001 = very slow (~6 s/cycle), 0.005 = fast (~1 s/cycle).

FAQ

No — it is pure DOM: 16 <div> elements with a linear-gradient CSS recalculated every frame by requestAnimationFrame. No canvas, no npm dependency. Copy the HTML, CSS, and JS into your project and the effect is ready.
Yes. Replace the call to getSimulatedAudio(count, time) inside animateSpectrumGradient with a function that reads from an AnalyserNode.getByteFrequencyData() buffer. The bars expect values in [0, 1] — normalize the first 16 bins of the Uint8Array (÷ 255) and pass them directly.
Add at the top of the script: const REDUCE = window.matchMedia('(prefers-reduced-motion: reduce)').matches;. In the animate function, conditionally schedule the next frame: if (!REDUCE) requestAnimationFrame(animate); — bars will hold their current height without looping.