โ† Lab Notes
August 3, 2026 homelabweb developmentmultiplayerjavascript

StringWeb: from a virtual guitar to a 7-instrument multiplayer jam app

This project evolved from a simple virtual guitar into a full-fledged multi-instrument browser-based jamming experience with sheet music, rhythm games, and real-time multiplayer.


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:

  1. Guitar: Uses a canvas fretboard for strumming.
  2. Bass: Similar to guitar but requires an exponential envelope layer due to its lower pitch range.
  3. Ukulele: Reentrant "high G" tuning, which makes it sound bright instead of like a tiny guitar.
  4. Piano: 8-pad kit with synthesized noise/oscillator hits.
  5. Drums: 8-pad kit with synthesized noise/oscillator hits.
  6. Trumpet: Uses three valve buttons that latch to select semitones, and a "blow" gesture to sound the note.
  7. 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:

  1. Double Counting in Rhythm Game: A single click registering as two hits on the same lane due to pointermove and pointerdown events. Fixed with an 80ms per-lane debounce.
  2. 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.
Was this useful?