A real-time, browser-based multiplayer beat-making game built with React, Tone.js, and WebRTC. Create collaborative jam sessions with up to 4 players, each controlling their own instruments and patterns.
- Multiplayer Lobbies: Support for up to 4 players in real-time collaborative sessions
- 6 Instrument Types: Drums, Bass, Melody, Harmony, Lead, Arpeggios
- 8 Patterns Per Instrument: Each instrument has 8 unique synthesized patterns
- Real-time Synchronization: All players hear changes instantly via P2P connections
- Multiple Players Per Instrument: Any number of players can play the same instrument type with different patterns
- Synthesized Audio: All sounds generated using Tone.js (no sample loading required)
- Global Controls:
- Tempo/BPM: Adjustable from 60-200 BPM
- Pitch Shift: Transpose entire session up/down 12 semitones
- Key Change: Musical key shifting for harmonic variations
- 16-Step Sequencing: Beat patterns loop every 16 steps
- Visual Beat Indicator: Real-time visual feedback of current beat position
- Export Functionality: Record and download your jam sessions as .webm audio files
- WebRTC P2P: Direct peer-to-peer communication for low-latency audio sync
- Simple Signaling Server: Lightweight Node.js/WebSocket server for connection establishment
- Mid-Session Join: Players joining during a session start on the next loop cycle
The interface features a retro-futuristic synthwave aesthetic:
- Neon color palette (pink, purple, cyan)
- Animated grid background
- Custom typography using Orbitron and Rajdhani fonts
- Smooth animations and glow effects
- Responsive design
- Node.js (v16 or higher)
- npm or yarn
- Install dependencies:
npm install- Start the signaling server:
npm run serverThe signaling server will start on port 8080.
- Start the client (in a new terminal):
npm startThe client will start on http://localhost:3000
-
Create a Lobby:
- Click "CREATE LOBBY" on the main menu
- Share the generated Lobby ID with other players
-
Join a Lobby:
- Enter the Lobby ID in the input field
- Click "JOIN LOBBY"
-
Make Music:
- Select your instrument from the 6 available options
- Choose one of 8 patterns for your instrument
- Press PLAY to start the beat
- Adjust global parameters (tempo, pitch, key) in real-time
- All players can change any parameter at any time
-
Record Your Session:
- Click "RECORD" to start recording
- Click "STOP REC" to stop and download the recording
- Frontend: React 18
- Audio Engine: Tone.js 14.7
- Networking: WebRTC + WebSocket (for signaling)
- Build Tool: Vite 5
- Server: Node.js with ws (WebSocket library)
synthjam-multiplayer/
├── signaling-server.js # WebSocket signaling server for WebRTC
├── BeatMakingGame.jsx # Main React component with game logic
├── main.jsx # React entry point
├── index.html # HTML template
├── vite.config.js # Vite configuration
├── package.json # Dependencies and scripts
└── README.md # This file
- Manages Tone.js synthesizers for each instrument type
- Handles pattern sequencing and playback
- Implements global parameters (BPM, transpose, key shift)
- Provides recording functionality via Tone.Recorder
- Establishes WebRTC peer connections
- Manages signaling via WebSocket
- Broadcasts state updates to all peers
- Handles peer join/leave events
- Renders UI for lobby and gameplay
- Manages local and remote player state
- Synchronizes audio with network state
- Handles user input and parameter changes
- Player Action → Local state update
- Local State → Broadcast to peers via WebRTC DataChannel
- Peer Receives → Update remote player state
- State Change → Audio engine updates patterns
- Audio Engine → Plays synchronized audio via Tone.js
Patterns are defined as arrays of 16 steps:
{
name: 'Pattern Name',
notes: ['C4', null, 'E4', null, ...] // or 'pattern' for drums
}null= silence- String = note to play (e.g., 'C4', 'A#2')
- Array = chord (for harmony/arpeggios)
- Membrane synth with exponential envelope
- Two main sounds: kick (C2) and snare (D2)
- Patterns range from four-on-the-floor to complex trap hi-hats
- Mono synth with sawtooth oscillator
- Lowpass filter for classic analog bass sound
- Patterns include walking bass, sub drops, funk lines, dubstep wobbles
- Polyphonic synth with triangle wave
- Patterns in major, minor, pentatonic scales
- Includes staccato, ambient, and ascending patterns
- Polyphonic synth with square wave
- Plays chords (major, minor, jazz voicings, power chords)
- Sustained and rhythmic stab patterns
- Mono synth with filter envelope
- High-energy patterns with octave jumps and trills
- Sparse and dense variations
- Polyphonic synth with sine wave
- Fast note sequences across chord progressions
- Ascending, descending, and randomized patterns
Edit BeatMakingGame.jsx line ~745:
networkManagerRef.current = new NetworkManager(
'ws://YOUR_SERVER_URL:PORT',
handleStateUpdate
);Edit signaling-server.js line ~60:
if (lobby.size >= 4) { // Change 4 to desired max playersAdd to the PATTERNS object in BeatMakingGame.jsx:
PATTERNS.yourInstrument.push({
name: 'New Pattern',
notes: ['C4', null, 'E4', ...] // 16 steps
});Deploy signaling-server.js to any Node.js hosting platform:
Heroku:
heroku create your-app-name
git push heroku mainDigitalOcean/AWS:
# SSH into your server
git clone your-repo
cd synthjam-multiplayer
npm install
PORT=8080 node signaling-server.jsUpdate the client code with your deployed server URL.
Build the client for production:
npm run buildDeploy the dist/ folder to any static hosting service:
- Netlify
- Vercel
- GitHub Pages
- Cloudflare Pages
The codebase is designed for easy extension:
- Add instrument to
INSTRUMENTSconstant - Add color to
INSTRUMENT_COLORS - Add 8 patterns to
PATTERNSobject - Add synth creation logic in
AudioEngine.createSynth()
Tone.js supports many audio effects:
const reverb = new Tone.Reverb().toDestination();
synth.connect(reverb);Add canvas-based visualizers using Tone.js analyzers:
const waveform = new Tone.Waveform();
Tone.getDestination().connect(waveform);- Browser Compatibility: Requires modern browsers with WebRTC support (Chrome, Firefox, Safari, Edge)
- Audio Context: Browsers require user interaction before playing audio (handled by the PLAY button)
- STUN Server: Uses Google's public STUN server for NAT traversal
- Recording Format: Exports as WebM audio (supported in most browsers)
"Failed to create lobby"
- Ensure signaling server is running on port 8080
- Check that WebSocket URL matches in the code
"No audio playing"
- Click the PLAY button to start audio context
- Check browser console for audio errors
- Ensure Tone.js initialized correctly
"Peers not connecting"
- Check firewall settings
- Verify WebRTC is enabled in browser
- Test with both clients on same network first
"Patterns out of sync"
- All clients must use same code version
- Network latency may cause slight delays
- Transport synchronization is handled by Tone.js
MIT License - Feel free to use, modify, and distribute this project.
Built with:
Made with 🎵 by the power of synthesis