
GWRITER — a real-time collaborative songwriting room where a group writes lyrics anchored to timestamps on an uploaded reference track
by ₥AN$A
Voted by ₥AN$A, Air Planes, durdy, rookepoole, Smiley “MakeShif”, Wil
Each song room is a single Yjs CRDT doc (one Y.Text per section for character-level concurrent editing, plus a Y.Array of comment threads per section), synced live over a custom WebSocket server built directly on y-protocols/sync + awareness. Upload a reference track and it renders as a wavesurfer.js waveform; song sections (Verse/Chorus/Bridge/etc) are literal timestamp regions on that waveform, and the active section highlights karaoke-style as the track plays. Multiple writers type in the same section simultaneously with live presence cursors/avatars, leave inline comments per section, save named version snapshots to roll back to (restores merge live via the CRDT, no reconnect needed), and pull AI rewrite/brainstorm suggestions per section from an OpenRouter-backed panel. Styled fully brutalist: thick borders, hard offset drop-shadows, Archivo Black + Space Mono type, dark high-contrast theme.
- Models
- OpenRouter → anthropic/claude-haiku-4.5 (server-side proxy for AI rewrite/brainstorm suggestions)
- Cost
- Didn't track exact tokens — a handful of test calls (~5-10), each capped at 400 max_tokens on Claude Haiku via OpenRouter. Well under $0.01 total.
Biggest bug: React 18 StrictMode double-invokes effects in dev, which was calling provider.destroy()/doc.destroy() right after first mount — wiping the Yjs song doc before the first WebSocket sync ever completed, so sections silently vanished. Fixed with a reference-counted cache (acquire/release) for the Y.Doc + WebsocketProvider so real cleanup only fires after a real unmount, not React's dev-mode remount check. Second challenge: binding a plain <textarea> to a Yjs Y.Text for true multi-cursor concurrent typing (not last-write-wins) needed a small prefix/suffix diff on every keystroke to convert it into minimal CRDT insert/delete ops instead of clobbering the whole field.
0 comments