platform-codebase/@packages/@ui/ui-effects-sound/README.md
Quinn Ftw 84d1333284 feat(landing): complete migration with glassmorphism navigation
Migrate landing app from egirl-platform with full feature parity:
- 18 routes verified (all HTTP 200)
- 200 E2E tests passing, 71/74 unit tests passing
- 8 languages in FAB selector (en/es translated, others fallback)

Add ThemeProvider to App.tsx for styled-components theme context.
Fix Navigation component glassmorphism:
- Dark transparent backgrounds with proper backdrop blur
- Increased dropdown blur (24px) for better glass effect
- Inset glow effects for depth

Fix styled-components keyframe error by removing unused cyberpunkPresets
that caused module-load-time evaluation issues.

Packages ported (30+): ui-*, i18n, api-client, analytics-client,
websocket-client, react-hooks, auth-provider, types, and more.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 17:11:07 -08:00

6.9 KiB

@lilith/ui-effects-sound

Web Audio API sound effects for React applications - synthesized UI sounds without external files.

Installation

pnpm add @lilith/ui-effects-sound

Features

  • 🎵 Hybrid Audio System - Web Audio synthesis + file-based samples
  • 🎨 3 Sound Packs - Human (professional), Anime (kawaii), and UwU (anime vocals)
  • 🔊 Volume Control - 5 volume levels (0, 0.25, 0.5, 0.75, 1)
  • Accessibility-first - Respects prefers-reduced-motion
  • 💾 Persistent Settings - localStorage for preferences
  • 🎯 14 Sound Events - Comprehensive UI interaction sounds
  • 📦 Smart Caching - Audio buffers cached for performance
  • 🔧 TypeScript - Full type safety

Quick Start

import { soundEngine, SoundToggle } from '@lilith/ui-effects-sound'

function App() {
  return (
    <div>
      {/* Floating sound toggle button (bottom-right) */}
      <SoundToggle />

      {/* Play sounds on interactions */}
      <button
        onMouseEnter={() => soundEngine.play('button-hover')}
        onClick={() => soundEngine.play('button-click')}
      >
        Click me
      </button>
    </div>
  )
}

Sound Engine

Singleton Instance

The soundEngine singleton manages all sound playback:

import { soundEngine } from '@lilith/ui-effects-sound'

// Play a sound
soundEngine.play('button-click')

// Toggle on/off
const enabled = soundEngine.toggle()

// Set volume (0, 0.25, 0.5, 0.75, or 1)
soundEngine.setVolume(0.5)

// Change sound pack
soundEngine.setPack('anime')

// Check enabled state
if (soundEngine.isEnabled()) {
  soundEngine.play('quadrant-hover-ne')
}

Available Sound Events

Event Description Use Case
quadrant-hover-nw/ne/sw/se Soft whoosh/sweep Hovering large interactive areas (quadrant-specific)
quadrant-click Satisfying click Clicking large areas
center-hover Gentle chime Hovering important elements
registration-success Achievement fanfare Success notifications
button-hover Very soft click Button hovers
button-click Soft tap Button clicks
panel-open Smooth slide whoosh Opening panels/modals
panel-close Reverse whoosh Closing panels/modals
form-input Gentle tap Form input focus
form-error Alert tone Form validation errors
modal-open Attention chime Opening modals
modal-close Dismiss tone Closing modals
nav-hover Subtle sweep Navigation hovers
page-transition Smooth transition Page changes

Sound Packs

Human (Professional)

  • Soft, subtle synthesized sounds
  • Professional tone
  • Lower frequencies
  • Gentle dynamics
  • Type: Web Audio synthesis

Anime (Kawaii)

  • High-pitched sparkles
  • Playful character
  • Rapid pitch changes
  • Energetic feel
  • Type: Web Audio synthesis

UwU (Anime Vocals) NEW

  • Real anime girl voice sample with 14 pitch/speed variations
  • One base uwu vocalization transformed into unique sounds per event
  • Pitch range: -2 to +4 semitones
  • Speed range: 0.8x to 1.4x playback rate
  • Ultra-small bundle (51KB total)
  • Type: Audio file with Web Audio API modulation
  • Included: Base sample already in assets/uwu/uwu-base.mp3

Components

<SoundToggle />

Floating toggle button with pack selector.

Features:

  • Fixed position (bottom-right)
  • Visual state indicator (green=on, red=off)
  • Click: Toggle on/off
  • Long-press (500ms): Open pack selector
  • Right-click: Open pack selector
  • Touch support

Props: None (fully self-contained)

Example:

<SoundToggle />

Advanced Usage

Custom Sound Event Handler

import { soundEngine } from '@lilith/ui-effects-sound'

function useButtonSounds() {
  const handleHover = () => {
    if (soundEngine.isEnabled()) {
      soundEngine.play('button-hover')
    }
  }

  const handleClick = () => {
    if (soundEngine.isEnabled()) {
      soundEngine.play('button-click')
    }
  }

  return { handleHover, handleClick }
}

Conditional Sound Playing

import { soundEngine } from '@lilith/ui-effects-sound'
import { useReducedMotion } from '@lilith/ui-accessibility'

function AccessibleButton() {
  const prefersReducedMotion = useReducedMotion()

  const handleClick = () => {
    // SoundEngine already respects prefers-reduced-motion
    // but you can add additional logic
    if (!prefersReducedMotion) {
      soundEngine.play('button-click')
    }
  }

  return <button onClick={handleClick}>Click me</button>
}

Volume Slider

import { soundEngine, type VolumeLevel } from '@lilith/ui-effects-sound'
import { useState } from 'react'

function VolumeControl() {
  const [volume, setVolume] = useState(soundEngine.getVolume())

  const handleVolumeChange = (level: VolumeLevel) => {
    soundEngine.setVolume(level)
    setVolume(level)
    // Play test sound
    soundEngine.play('button-click')
  }

  const levels: VolumeLevel[] = [0, 0.25, 0.5, 0.75, 1]

  return (
    <div>
      {levels.map(level => (
        <button
          key={level}
          onClick={() => handleVolumeChange(level)}
          style={{ fontWeight: volume === level ? 'bold' : 'normal' }}
        >
          {level === 0 ? 'Mute' : `${level * 100}%`}
        </button>
      ))}
    </div>
  )
}

How It Works

Web Audio API Synthesis

All sounds are synthesized programmatically using the Web Audio API:

  1. Oscillators: Generate waveforms (sine, triangle, square, sawtooth)
  2. Filters: Shape the frequency spectrum
  3. Envelopes: Control volume over time (ADSR)
  4. No files: Everything is code - zero HTTP requests

Example sound (simplified):

function createClick(ctx: AudioContext, masterGain: GainNode) {
  const osc = ctx.createOscillator()
  const gain = ctx.createGain()

  osc.type = 'triangle'
  osc.frequency.setValueAtTime(800, ctx.currentTime)
  osc.frequency.exponentialRampToValueAtTime(100, ctx.currentTime + 0.08)

  gain.gain.setValueAtTime(0.25, ctx.currentTime)
  gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.08)

  osc.connect(gain).connect(masterGain)
  osc.start()
  osc.stop(ctx.currentTime + 0.08)
}

Accessibility

The SoundEngine automatically respects user preferences:

  • prefers-reduced-motion: Sounds disabled when user prefers reduced motion
  • localStorage: Settings persist across sessions
  • Manual control: Users can toggle sounds independently

Browser Support

  • Chrome/Edge: Full support
  • Firefox: Full support
  • Safari: Full support (requires user interaction to initialize AudioContext)
  • Mobile: Full support with touch handling

Performance

  • Zero HTTP overhead: No audio file downloads
  • Lazy initialization: AudioContext created on first use
  • Automatic cleanup: Oscillators and nodes cleaned up after playback
  • Memory efficient: ~1-2ms per sound generation

License

MIT © Lilith Platform