Overview
StringWeb is a browser-based multi-instrument toy that started as a single virtual guitar and grew into a seven-instrument jam app. The project was completed over two days in August 2026, with the source code split between plain HTML/CSS/JS and a Node.js WebSocket relay for real-time multiplayer functionality.
Background
The idea for StringWeb originated from an Idea Pipeline project called "stringweb." After initial development, it was moved to the ~/breadtoasting/stringweb directory to align with other live projects on the site. The core engine uses Karplus-Strong synthesis for realistic plucked string sounds and supports multiple instruments like guitar, bass, ukulele, piano, drums, trumpet, and saxophone.
How It Works
Core Engine (Guitar/Bass/Ukulele)
The core of StringWeb is built around a canvas fretboard where users can strum strings by hovering over them. Clicking on a fret holds it, while clicking again releases it. Tuning pegs allow for detuning each string in cents offsets with preset values like Drop D and Open G.
For the bass, additional processing was required due to its lower pitch range. The Karplus-Strong synthesis needed an exponential envelope layer to avoid excessive reverb. Testing confirmed that both guitar and bass started equally loud but quickly diverged, with the bass being about 10 times quieter by 300ms.
Instruments
StringWeb supports seven instruments:
- Guitar: Uses a canvas fretboard for strumming.
- Bass: Similar to guitar but requires an exponential envelope layer due to its lower pitch range.
- Ukulele: Reentrant "high G" tuning, which makes it sound bright instead of like a tiny guitar.
- Piano: 8-pad kit with synthesized noise/oscillator hits.
- Drums: 8-pad kit with synthesized noise/oscillator hits.
- Trumpet: Uses three valve buttons that latch to select semitones, and a "blow" gesture to sound the note.
- Saxophone: Six tone-hole buttons in recorder/tin-whistle style.
All instruments share a common tab line abstraction for playing and recording notes.
Sheet Music
Sheet music is entered using standard ASCII tab notation (one line per string/key/pad). The currentTabLines() function handles this across all instruments, allowing users to play back the same tab text format as their recordings. This also serves as the export/save mechanism.
Rhythm Game
The rhythm game was initially designed with falling notes but quickly became unplayable due to conflating visual and input handling. It was rebuilt as a Guitar-Hero-style vertical note highway, with two-tier judgment (Perfect within 70ms, Good within 160ms) and combo scoring.
Three curated "songs" are provided: Warm-Up, Steady Groove, and Fast Fill. These songs are built using short 8-step patterns strung into a bar arrangement, adapting to the number of lanes for each instrument.
Multiplayer
The multiplayer feature uses a Node.js WebSocket relay (stringweb-relay) to manage real-time interactions between multiple browsers. The relay service is proxied through Nginx with standard WebSocket-upgrade headers. Note events are sent over the network, and each browser re-synthesizes sounds locally to avoid audio latency issues.
Bugs and Fixes
Two significant bugs were identified during development:
- Double Counting in Rhythm Game: A single click registering as two hits on the same lane due to
pointermoveandpointerdownevents. Fixed with an 80ms per-lane debounce. - Saxophone Pitch Calculation Bug: The note list was sorted high-to-low for tab display, but the pitch calculation function still used the original order. Fixed by computing the pitch directly from scale-degree formulas.
Results
StringWeb is currently live at breadtoasting.com/stringweb/ and supports seven playable instruments, sheet music with tab-style notation, a recording feature that captures live playing into tab format, a rhythm game with built-in songs, and real-time multiplayer jam sessions via an invite link. The project has no known open bugs.
Lessons Learned
Count-based test assertions and pure code review missed two user-facing bugs: one where the feature was unplayable, and another where it played incorrect notes. Testing actual observable outputs (real browser interactions or literal frequency values) caught both issues.
The project also highlighted the importance of considering real-world constraints like mouse clicks for complex instrument behaviors, such as latching valve buttons on a trumpet.
TODO:
- More instruments beyond the current seven (violin, synth pad, flute).
- Additional features based on user feedback and interest.