scrawl
Highlights
- No shell, no exec — wish hands each SSH connection straight to a bubbletea program, structurally incapable of reaching a real shell on the host, same model as delve-term
- Live multiplayer state: a small in-memory registry of every connected session's *tea.Program broadcasts a redraw the instant anyone paints
- Found and fixed a real deadlock — Program.Send() blocks until Run() is actively reading, so broadcasting synchronously from Join()/Paint() froze every session before it ever rendered; fixed with go p.Send(...)
- Found and fixed a subtler bug — lipgloss's default styles detect color support from the server process's own stdout, not any session's actual terminal, so a redirected log file silently killed all color/background styling server-wide; fixed with a per-session lipgloss.Renderer forced to TrueColor
- Verified with two scripted concurrent SSH sessions, not just live poking — one paints, the other sees the broadcast, peer count stays in sync
A shared ASCII doodle wall reachable over raw SSH — connect and you’re painting on the same canvas as everyone else connected right now, live.
ssh scraw.games.goonk.se -p 23235
Not aiming to be useful to anyone but me. Built purely because a multiplayer canvas over SSH is a fun, weird shape for a toy, and the wish+bubbletea pattern from delve-term was still fresh enough to reuse without re-learning it. The one thing this app needed beyond that pattern: multiple sessions sharing live state, which meant building the tea.Program directly instead of hiding behind wish’s usual middleware helper, so a small registry could hold a reference to every connected session and broadcast a redraw the instant one of them paints.
Two real, subtle bugs came out of that: a synchronous broadcast that deadlocked the very first connection before it ever rendered anything, and a color-detection quirk in lipgloss that silently stripped all color server-wide because it was reading the server process’s own (redirected) stdout instead of each session’s actual terminal. Both fixed, both covered by regression tests.