Inspiration

Chat is the best clip detector a streamer has. When chat erupts, something worth clipping just happened, but after a four hour stream nobody remembers where. Seismologists solved this exact problem a century ago: find the moments when a quiet signal suddenly spikes far above its own background. So we pointed a seismograph at Twitch chat.

What it does

Chatquake is a free OBS browser source plus a quake catalog for any Twitch channel. No keys, no login, no download: type your channel, paste the overlay URL into a Browser Source.

  • Live seismogram. A red pen draws chat activity on seismograph paper. Quiet chat is a flat line, each message is a small blip, an eruption swings the pen to the edge.
  • Quakes. When chat erupts, Chatquake calls a quake with a magnitude, an epicenter (the emote or word that dominated) and message and chatter counts. A stamped alert slides in and the panel shakes in proportion to the magnitude (off with reduced motion or shake=0).
  • Did you feel it? Viewers type !felt, like the USGS "Did You Feel It?" survey. The felt meter climbs a Modified Mercalli style scale from I to X.
  • Recent quakes and aftershocks. A USGS style feed of the last quakes, aftershock linking, and an Omori law forecast of the odds of another eruption in the next five minutes.
  • The catalog. Every quake is logged with time, offset into the stream, magnitude, epicenter, chatters and felt intensity. Export CSV or JSON, or copy YouTube chapters, so editors and clippers start from the moments chat already voted on.
  • Broadcaster controls from chat. !cq mark boss down adds a named timestamp, !cq test fires a test quake to check the scene, !cq reset starts a new session. Only the broadcaster and mods can use them.
  • Fair to small channels. Magnitude is relative to each channel's own baseline: M = 1 + 2 log10(peak STA/LTA) + 0.6 log10(1 + chatters). Five viewers can shake the room as hard as fifty thousand.

How it connects to Twitch

The overlay and the catalog each join the channel's chat read-only and anonymously over Twitch's official chat WebSocket (wss://irc-ws.chat.twitch.tv), parse IRCv3 tags for badges, emotes and user ids, render Twitch emotes from the public CDN, and reconnect with exponential backoff. Nothing is stored server side; the catalog lives in the streamer's browser. In the video, the messages are real Twitch chat typed live in the channel, shown in Twitch's own chat embed next to the overlay.

How we built it with Codex

All of the code was written by OpenAI Codex (codex-cli, gpt-6-astra) in one thread over three turns. I wrote the product brief and reviewed every turn in a real browser.

  1. Build. A full brief: product, constraints (static site, no runtime dependencies, no keys), the detection math, file layout and test plan. Codex wrote the IRC parser and reconnecting client, the STA/LTA seismology engine with an injected clock, the canvas drum, the overlay, catalog and landing pages, and a live Twitch smoke test. Its first test run caught an IRC tag unescaping bug, which it fixed.
  2. Review from screenshots. I ran it in headless Chrome and sent Codex the screenshots: quakes never ended (the frozen baseline kept the ratio high), the trace was always full height, and the code was too dense. Codex added a peak-relative detrigger and a 90 second cap, a logarithmic pen envelope with per-message kicks, stamped alerts, the recent quakes feed, the felt meter, realistic demo pacing and a full reformat, each engine fix with a regression test.
  3. Review from a live test. On a real channel with real chat the overlay never connected: the browser threw "Illegal invocation" because Codex had stored setTimeout and clearTimeout unbound. Node never shows that, so all tests had passed. Codex bound the builtins, audited the rest, and added a test that simulates browser this semantics so it cannot come back.

The result: 38 tests on Node's built-in runner, zero runtime dependencies, deployable as plain static files.

Challenges we ran into

  • Making magnitude meaningful for both tiny and huge channels. A fixed messages-per-second threshold fails both, so the trigger is the classic STA/LTA ratio against the channel's own rolling baseline, with a warmup and a frozen baseline during shaking.
  • Deciding when a quake ends. Real chat stays excited after a big moment; the fix was a detrigger relative to the quake's own peak plus a hard cap.
  • Browser-only bugs that unit tests in Node could not see.

What's next

Optional OAuth mode so the bot can reply with !quake summaries and create real Twitch stream markers at each quake, and a VOD replay mode that runs the catalog over a past broadcast's chat.

Try it

Built With

Share this project:

Updates

Submission history