No description
Find a file
autocommit b91af80dad
Some checks failed
Publish / publish (push) Failing after 0s
deps-upgrade(deps): ⬆️ Update all dependencies to latest stable versions
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-10 21:21:38 -07:00
.forgejo/workflows chore: initial package split from monorepo 2026-04-20 01:10:55 -07:00
assets/uwu chore: initial package split from monorepo 2026-04-20 01:10:55 -07:00
src chore: initial package split from monorepo 2026-04-20 01:10:55 -07:00
tools chore: initial package split from monorepo 2026-04-20 01:10:55 -07:00
.gitignore chore: add .gitignore, remove node_modules/dist/.turbo from tracking 2026-04-20 01:12:50 -07:00
eslint.config.js chore: initial package split from monorepo 2026-04-20 01:10:55 -07:00
package.json deps-upgrade(deps): ⬆️ Update all dependencies to latest stable versions 2026-06-10 21:21:38 -07:00
README.md chore: initial package split from monorepo 2026-04-20 01:10:55 -07:00
test-uwu-simple.html chore: initial package split from monorepo 2026-04-20 01:10:55 -07:00
tsconfig.json chore: initial package split from monorepo 2026-04-20 01:10:55 -07:00
tsconfig.tsbuildinfo chore: initial package split from monorepo 2026-04-20 01:10:55 -07:00

@ui/effects-sound

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

Installation

pnpm add @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 '@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 '@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 '@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 '@ui/effects-sound'
import { useReducedMotion } from '@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 '@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