Skip to main content

Overview

Web XP includes authentic Windows XP system sounds for boot, login, logout, shutdown, and error events. The sound system uses the VolumeContext for centralized volume control and supports custom sound additions.

Available System Sounds

The project includes 40+ Windows XP sound files located in src/assets/sounds/:

Primary System Sounds

  • xp_startup.wav - Boot/startup sound (424KB)
  • xp_logon.wav - Login sound (190KB)
  • xp_logoff.wav - Logout sound (179KB)
  • xp_shutdown.wav - Shutdown sound (282KB)
  • error.wav - Error dialog sound (44KB)

Additional Sounds

  • Windows XP Start.wav - Start menu click
  • Windows XP Error.wav - Error notifications
  • Windows XP Exclamation.wav - Warning dialogs
  • Windows XP Ding.wav - Information alerts
  • Windows XP Notify.wav - System notifications
  • Windows XP Minimize.wav - Window minimize
  • Windows XP Restore.wav - Window restore
  • Windows XP Recycle.wav - Recycle bin
  • Windows XP Menu Command.wav - Menu clicks
  • Windows XP Hardware Insert.wav - Device connected
  • Windows XP Hardware Remove.wav - Device disconnected
  • Windows XP Hardware Fail.wav - Device error
  • Windows XP Critical Stop.wav - Critical errors
  • Windows XP Battery Low.wav - Low battery warning
  • Windows XP Battery Critical.wav - Critical battery
  • Windows XP Pop-up Blocked.wav - Popup blocker
  • Windows XP Information Bar.wav - Info bar
  • xp_balloon.wav - Tooltip/balloon
  • chord.wav, chimes.wav, tada.wav - Classic sounds
  • ringin.wav, ringout.wav - Call sounds

VolumeContext

Context Provider

The VolumeContext manages global volume and mute state with localStorage persistence (src/context/VolumeContext.jsx:1-41):
import { createContext, useState, useEffect, useContext } from 'react';

const VolumeContext = createContext();

export const useVolume = () => useContext(VolumeContext);

export const VolumeProvider = ({ children }) => {
  const [volume, setVolume] = useState(() => {
    const savedVolume = localStorage.getItem('siteVolume');
    return savedVolume !== null ? JSON.parse(savedVolume) : 50;
  });

  const [isMuted, setIsMuted] = useState(() => {
    const savedMute = localStorage.getItem('siteMuted');
    return savedMute !== null ? JSON.parse(savedMute) : false;
  });

  useEffect(() => {
    localStorage.setItem('siteVolume', JSON.stringify(volume));
  }, [volume]);

  useEffect(() => {
    localStorage.setItem('siteMuted', JSON.stringify(isMuted));
  }, [isMuted]);

  const applyVolume = audio => {
    if (audio) {
      audio.volume = volume / 100;
      audio.muted = isMuted;
    }
  };

  return (
    <VolumeContext.Provider
      value={{ volume, setVolume, isMuted, setIsMuted, applyVolume }}
    >
      {children}
    </VolumeContext.Provider>
  );
};

Setup in Application

The VolumeProvider wraps the entire app (src/App.jsx:180-186):
function App() {
  return (
    <VolumeProvider>
      <AppLogic />
    </VolumeProvider>
  );
}

Audio Playback Implementation

Basic Sound Playback

The standard playback function (src/App.jsx:29-43):
const { applyVolume } = useVolume();

const playSound = useCallback(
  soundSrc => {
    if (!soundSrc) return;
    try {
      const audio = new Audio(soundSrc);
      if (typeof applyVolume === 'function') {
        applyVolume(audio);
      }
      audio.play().catch(() => {});
    } catch (error) {
      // Failed to play sound
    }
  },
  [applyVolume],
);

System Event Sounds

Sounds are imported and played on specific events (src/App.jsx:10-13):
import xpStartupSoundSrc from 'assets/sounds/xp_startup.wav';
import xpLogonSoundSrc from 'assets/sounds/xp_logon.wav';
import xpShutdownSoundSrc from 'assets/sounds/xp_shutdown.wav';
import xpErrorSoundSrc from 'assets/sounds/error.wav';

// Play on login
const handleLogin = useCallback(() => {
  if (skillzSessionStatus === 'loggedInInBackground') {
    playSound(xpLogonSoundSrc);
    setScreen('desktop');
  } else {
    playSound(xpStartupSoundSrc);
    setScreen('welcome');
  }
}, [skillzSessionStatus, playSound]);

// Play on shutdown
const handleInitiateShutdownFromLogin = useCallback(() => {
  playSound(xpShutdownSoundSrc);
  setShutdownMessages(['Windows is shutting down...']);
  setScreen('shuttingDown');
}, [playSound]);

Desktop Sounds

For sounds within the desktop environment (src/WinXP/index.jsx:28-44):
import xpLogoffSoundSrc from 'assets/sounds/xp_logoff.wav';
import xpShutdownSoundSrc from 'assets/sounds/xp_shutdown.wav';
import { useVolume } from '../context/VolumeContext';

const playSound = (soundSrc, applyVolume) => {
  if (!soundSrc) return;
  try {
    const audio = new Audio(soundSrc);
    if (typeof applyVolume === 'function') {
      applyVolume(audio);
    }
    audio.play().catch(() => {});
  } catch (error) {
    // Failed to play sound
  }
};

const { applyVolume } = useVolume();

const playSoundWithVolume = useCallback(
  soundSrc => {
    playSound(soundSrc, applyVolume);
  },
  [applyVolume],
);

Volume Control UI

The volume slider appears when clicking the speaker icon in the taskbar (src/WinXP/Footer/index.jsx:11-12,43-46):
import { useVolume } from '../../context/VolumeContext';
import VolumeSlider from '../../components/VolumeSlider';

const { volume, setVolume, isMuted, setIsMuted } = useVolume();

// Volume slider popup
{showVolume && (
  <VolumeSlider
    volume={volume}
    onVolumeChange={setVolume}
    isMuted={isMuted}
    onMuteChange={setIsMuted}
  />
)}

VolumeSlider Component

The slider component (src/components/VolumeSlider/index.jsx:69-102):
function VolumeSlider({ volume, onVolumeChange, isMuted, onMuteChange }) {
  const handleSliderChange = e => {
    onVolumeChange(Number(e.target.value));
    // Auto-unmute when adjusting slider
    if (isMuted) {
      onMuteChange(false);
    }
  };

  const handleCheckboxChange = e => {
    onMuteChange(e.target.checked);
  };

  return (
    <SliderWrapper>
      <Title>Volume</Title>
      <Slider
        type="range"
        min="0"
        max="100"
        value={isMuted ? 0 : volume}
        onChange={handleSliderChange}
      />
      <MuteContainer>
        <input
          type="checkbox"
          checked={isMuted}
          onChange={handleCheckboxChange}
        />
        Mute
      </MuteContainer>
    </SliderWrapper>
  );
}

Adding Custom Sounds

1. Add Sound File

Place your .wav file in src/assets/sounds/:
src/assets/sounds/custom_sound.wav

2. Import the Sound

Import it in your component:
import customSound from 'assets/sounds/custom_sound.wav';

3. Play with Volume Control

Use the playSound pattern:
import { useVolume } from './context/VolumeContext';

function MyComponent() {
  const { applyVolume } = useVolume();

  const playCustomSound = () => {
    const audio = new Audio(customSound);
    applyVolume(audio);
    audio.play().catch(() => {});
  };

  return <button onClick={playCustomSound}>Play Sound</button>;
}

4. Add to System Events

To play on specific events, add to the appropriate handler:
const handleCustomEvent = () => {
  playSound(customSound);
  // ... rest of event logic
};

Best Practices

  1. Always Use applyVolume: Ensures sounds respect user volume settings
  2. Handle Errors Gracefully: Use try-catch and empty catch blocks for play() promises
  3. Use .wav Format: For compatibility with Windows XP aesthetic
  4. Keep Files Small: Compress audio files to reduce bundle size
  5. Avoid Autoplay: Only play sounds in response to user actions
  6. Test Mute State: Ensure sounds respect the mute setting

Sound File Sizes

Be mindful of audio file sizes. The current sounds range from:
  • Small: 1-5KB (menu clicks)
  • Medium: 20-50KB (notifications)
  • Large: 100-400KB (startup/shutdown)
  • src/context/VolumeContext.jsx - Volume management
  • src/components/VolumeSlider/index.jsx - Volume UI control
  • src/App.jsx - Boot/login/logout sounds
  • src/WinXP/index.jsx - Desktop sound playback
  • src/WinXP/Footer/index.jsx - Volume icon and slider
  • src/assets/sounds/ - All sound files

Build docs developers (and LLMs) love