Online Piano
A collaborative virtual piano in the browser: a full keyboard, shared rooms, and a small set of sounds that are good enough to get lost in.
Stack TypeScript · React · Web Audio · WebSockets
The browser has had a capable audio engine for years, and most online pianos still sound like a MIDI file from 1998. This one started with a simpler question: can two people open the same page and play together without installing anything?
The answer is yes, with caveats. The keyboard is the easy part. The interesting problems are latency, note ownership, and the moment when two people try to play the same key.
The interface
The piano takes the whole screen. The keys are the interface; there is no sidebar, no settings panel, and no onboarding modal. A room code sits in the corner. When someone else joins, their cursor appears on the keyboard and their notes are tinted a second colour.
The sound is synthesised in the browser with Web Audio. Each note is a small envelope rather than a sample, which keeps the payload tiny and makes the keyboard feel immediate. The trade is timbre: it will not fool a pianist, but it responds like an instrument, and that matters more for the first five minutes.
The build
React and TypeScript with a Web Audio engine outside the render tree. The audio graph is created once and reused; the UI only schedules notes and releases them. Room state lives in a small WebSocket server, with each key press carrying a timestamp so late messages can be dropped instead of played out of time.
The hardest bug was key repeat. A held key generates repeated events on some keyboards, and the naive implementation retriggered the note on every event. The fix was a pressed-key set keyed by physical code, not by the character produced. It is the kind of bug that is obvious in retrospect and invisible in a demo.
NOTE
Latency is not a number. It is the difference between playing an instrument and operating a remote control.
What I would keep
The shared cursor. Seeing another person’s hand on the keyboard is worth more than a chat box, a user list, or a latency readout. It makes the room feel occupied.