Skip to main content
Open Tarteel includes a dynamic audio visualizer that displays animated bars synchronized to the Quran recitation, providing visual feedback during playback.

Overview

The audio visualizer creates a real-time visual representation of the audio frequency spectrum, displaying animated bars that respond to the recitation.
The visualizer uses the Web Audio API to analyze audio in real-time and render frequency data as animated bars.

Enabling the Visualizer

The visualizer can be toggled on or off:
Click the spectrum icon in the player controls to toggle the visualizer.The icon changes appearance:
  • Colored icon - Visualizer is on
  • Gray icon - Visualizer is off
The visualizer cannot be toggled while audio is playing. Pause playback first, toggle the visualizer, then resume playing.

Visualizer Component

The visualizer is implemented using react-audio-spectrum:
// From audio-bars-visualizer.tsx:14-59
export default function AudioBarsVisualizer({
  audioId,
  isPlaying,
}: AudioVisualizerProps) {
  const showVisualizer = useAtomValue(showVisualizerAtom);
  const [visualizerWidth, setVisualizerWidth] = useState(400);

  useEffect(() => {
    const calculateWidth = () => {
      setVisualizerWidth(Math.min(window.innerWidth * 0.8, 400));
    };
    calculateWidth();
    window.addEventListener('resize', calculateWidth);
    return () => window.removeEventListener('resize', calculateWidth);
  }, []);

  if (!showVisualizer) return <></>;
  
  if (!isPlaying) {
    return <div className="mb-2 flex h-[90px] w-full max-w-md justify-center" />;
  }

  return (
    <div className="mb-2 flex h-[90px] w-full max-w-md justify-center">
      <ReactAudioSpectrum
        id="audio-spectrum"
        audioId={audioId}
        height={90}
        width={visualizerWidth}
        capColor="#0191e2"
        meterWidth={10}
        meterColor="#0191e2"
        gap={4}
        silent={!isPlaying}
      />
    </div>
  );
}

Visualizer Features

Frequency Bars

Animated bars representing audio frequencies

Real-time Sync

Responds instantly to audio changes

Responsive Width

Adapts to screen size automatically

Color Customization

Blue theme (#0191e2) matching app design

Visual Specifications

Dimensions

  • Height: 90 pixels (fixed)
  • Width: Up to 400 pixels (responsive)
  • Bar Width: 10 pixels
  • Gap: 4 pixels between bars

Responsive Behavior

// From audio-bars-visualizer.tsx:21-33
useEffect(() => {
  const calculateWidth = () => {
    setVisualizerWidth(Math.min(window.innerWidth * 0.8, 400));
  };

  calculateWidth();
  window.addEventListener('resize', calculateWidth);
  
  return () => {
    window.removeEventListener('resize', calculateWidth);
  };
}, []);
The visualizer width:
  • Takes 80% of window width
  • Maximum 400 pixels
  • Recalculates on window resize
  • Maintains aspect ratio
On mobile devices, the visualizer automatically shrinks to fit the screen while maintaining readability.

Color Scheme

#0191e2 - Bright blueThe main color of the frequency bars, chosen to match Open Tarteel’s brand colors.

Playback States

The visualizer responds to different playback states:

When Visualizer is Disabled

if (!showVisualizer) {
  return <></>;
}
No space is reserved - the component renders nothing.

When Paused

if (!isPlaying) {
  return <div className="mb-2 flex h-[90px] w-full max-w-md justify-center" />;
}
Space is reserved (90px height) but no bars are shown.

When Playing

Full visualizer renders with animated bars responding to audio frequencies.
  • Off → On: Visualizer fades in smoothly
  • Paused → Playing: Bars animate from silence
  • Playing → Paused: Bars drop to zero
  • On → Off: Component unmounts, space collapses

Audio Analysis

The visualizer connects to the audio element:
<ReactAudioSpectrum
  id="audio-spectrum"
  audioId={audioId}          // Links to <audio id="audio">
  height={90}
  width={visualizerWidth}
  capColor="#0191e2"
  meterWidth={10}
  meterColor="#0191e2"
  gap={4}
  silent={!isPlaying}        // Stops animation when paused
/>

How It Works

  1. Audio Element - References the main audio player by ID
  2. Web Audio API - Creates an AnalyserNode to process audio
  3. FFT Analysis - Performs Fast Fourier Transform on audio data
  4. Frequency Data - Extracts frequency bins from analysis
  5. Visualization - Maps frequency data to bar heights
  6. Animation Loop - Updates at 60 FPS using requestAnimationFrame
The visualizer uses the Web Audio API’s AnalyserNode, which analyzes audio without affecting playback or quality.

Persistence

The visualizer setting is persisted across sessions:
// From atom.ts:21-24
export const showVisualizerAtom = createAtomWithStorage<boolean>(
  'show-visualizer',
  true  // Default: enabled
);

Storage Features

  • LocalStorage Key: show-visualizer
  • Default Value: true (enabled by default)
  • Type: Boolean
  • Persistence: Survives browser restarts
New users see the visualizer by default. Once toggled, the preference is remembered for all future sessions.

Integration with Player

The visualizer is integrated into the main player:
// From player.tsx:204
<AudioBarsVisualizer audioId="audio" isPlaying={isPlaying} />
It receives:
  • audioId: Reference to the audio element
  • isPlaying: Current playback state

Player Layout

Visualizer appears:
  • Above player controls
  • Below reciter selector (when visible)
  • Centered horizontally
  • With 0.5rem bottom margin

Toggle Control

The visualizer toggle button shows:
// From player-controls.tsx:559-565
{renderImageButton(
  showVisualizer ? spectrumSVG : spectrumDisabledSVG,
  showVisualizer ? messages.hideVisualizer : messages.showVisualizer,
  () => setShowVisualizer((previous) => !previous),
  isPlaying ? 'pointer-events-none cursor-not-allowed opacity-30' : '',
  isPlaying
)}

Button States

Enabled

Colored spectrum icon, clickable

Disabled

Gray spectrum icon, clickable

While Playing

Reduced opacity, not clickable

Tooltip

Shows current state on hover
The toggle is disabled during playback to prevent audio glitches that could occur when connecting/disconnecting the audio analyzer.

Performance

The visualizer is optimized for performance:

Efficient Rendering

  • Uses Canvas API for 60 FPS animation
  • Minimal React re-renders
  • Debounced resize handler
  • Conditional rendering based on state

Resource Usage

  • CPU: Low impact, uses GPU acceleration when available
  • Memory: ~2-5 MB for audio analysis buffers
  • Battery: Minimal impact on mobile devices
The visualizer automatically stops consuming resources when playback is paused or the visualizer is disabled.

Browser Compatibility

The visualizer requires Web Audio API support:
  • Chrome/Edge 35+
  • Firefox 25+
  • Safari 14.1+
  • Opera 22+
  • All modern mobile browsers

Customization

The visualizer appearance is controlled by props:
{
  height: 90,              // Bar container height
  width: visualizerWidth,  // Responsive width
  capColor: '#0191e2',     // Peak indicator color
  meterWidth: 10,          // Individual bar width
  meterColor: '#0191e2',   // Bar fill color
  gap: 4,                  // Space between bars
  silent: !isPlaying       // Animation control
}

Customizable Properties

  • Height: Overall visualizer height in pixels
  • Width: Overall visualizer width in pixels
  • Cap Color: Peak indicator color (hex/rgb)
  • Meter Width: Width of each frequency bar
  • Meter Color: Color of frequency bars
  • Gap: Spacing between bars in pixels
  • Silent: Pause animation while maintaining display
To customize colors, modify the capColor and meterColor props in audio-bars-visualizer.tsx:51-52.

Accessibility

The visualizer is decorative and accessibility-friendly:
  • Hidden from screen readers (no semantic meaning)
  • Doesn’t interfere with keyboard navigation
  • Optional feature (can be disabled)
  • No critical information displayed
  • Color contrast not critical (decorative only)
Users who prefer reduced motion can disable the visualizer for a simpler, static interface.

Troubleshooting

Visualizer not showing?
  • Check that it’s enabled in settings
  • Verify audio is playing (not paused)
  • Check browser Web Audio API support
  • Try refreshing the page
Bars not moving?
  • Ensure audio is actually playing
  • Check audio source is valid
  • Verify silent prop is false
  • Look for console errors
Performance issues?
  • Try disabling visualizer on low-end devices
  • Close other tabs consuming resources
  • Update browser to latest version
  • Check hardware acceleration is enabled

Build docs developers (and LLMs) love