Inspiration
Small streamers collab all the time, but a collab usually means two people side by side while each chat keeps watching its own screen. Raids move viewers one way, once. We wanted a moment that only exists when both communities show up together: the stadium card stunt, where thousands of people each hold up one card and a picture appears that nobody could see from their own seat. Except here the stadium is split across two broadcasts.
What it does
Crossover Stunt is a transparent 1920×1080 OBS browser source. One hidden pixel picture is split across two Twitch streams: stream A shows the left half, stream B the right half.
- Call. One streamer picks a picture (a preset, text, or their own image) and presses Call the stunt. A bot posts in both chats and the cards rise on both streams.
- People, not messages. Every distinct person who types anything sharpens their side's half. Spam, repeats, our own bot and known chat bots add nothing.
- Visible waiting. A finished side shows
WAITING FOR <partner>; the other stream seesTHEY'RE WAITING ON YOU. The bot invites the finished chat to hop over and help — people who type in both chats count as crossovers. - The wave. When both sides reach their quorum, a stadium wave carries the picture from stream A across the seam into stream B on one shared server clock, then a stats card on both streams: people, streams, and how many crossed over to help the other side.
- Stakes. If time runs out:
SO CLOSE, no reveal. - No partner needed. Single-channel mode turns any chat into a card stunt, and
pnpm demo --autoplayruns everything with a clearly labeled SIMULATED crowd and no Twitch account.
The pictures are designed so neither chat can read them alone: HYPE is HY on one stream and PE on the other.
How we built it
Built with OpenAI Codex, in a few Codex threads, the main one being session 01a194b7-1fa1-7df1-9213-da7b4c07bf8b:
- Rules first. Codex scaffolded the strict TypeScript / Vitest / Playwright toolchain and wrote
AGENTS.md(pure engine, never render chat text or usernames, no secrets, label anything simulated) plus three Codex skills:twitch-eventsub,stunt-engine,overlay-visual-check. - Review. A full Codex review found 11 real bugs, each fixed with a regression test.
- Live fixes and features. Codex fixed what the first real Twitch test broke and built the waiting cues, the finale, team labels, the bot invite line and the facecam layouts.
- Broadcast redesign. From an art-direction brief, Codex rebuilt the whole visual system: Archivo + Geist Mono, a sports-style score bug with rolling tabular digits, glass lower-thirds with one accent, matte cards with a real flip, the stadium wave, and an Apple-style control panel. It captured 35 states, wrote a critique of every screenshot, and iterated.
- Fixing what the live stream found. We streamed the redesign on both channels; three defects only showed up on the real broadcast. Codex fixed them in the same thread with regression tests, and a second live stream confirmed the fixes.
Under the hood:
- Engine: a pure, deterministic reducer
step(state, event, now)with fast-check property tests (spam invariance, duplicate delivery, deadline boundary, reveal gating, deterministic replay). - Refinement: a greedy quadtree. Each step splits the block with the largest colour error, and each side shows
steps(progress)of its plan, where
$$\text{progress}_s = \min\left(1,\ \frac{\left|\text{people}_s\right|}{q_s}\right), \qquad q_s = \max\left(3,\ \left\lceil 0.4 \cdot \text{recent chatters}_s \right\rceil\right)$$
The last ~20 % of the detail stays locked until both sides are ready, so a finished half still can't spoil the picture.
- Twitch: one EventSub WebSocket with two
channel.chat.messagesubscriptions on one user token, the Device Code flow with a public client (no secret, no redirect server), Helix Send Chat Message for the bot lines, and Shared-Chat-aware dedupe. No Affiliate status, Extension, bits or channel points needed. - Sync: the server owns the clock. Overlays get aggregate snapshots over a WebSocket (with HTTP polling fallback) and schedule the wave from server timestamps, so it crosses the seam at the same instant on both broadcasts.
- Privacy: nothing from chat — no names, no messages — ever reaches the overlay. Only counts and the picture.
- Tests: 260 Vitest tests and 80 Playwright browser tests, including a pixel test that the two overlays meet exactly at the seam (columns 47 | 48).
Challenges we ran into
- Two streams, one moment. Two independent broadcasts with their own delay had to feel like one stadium. We moved all timing to the server and animate from timestamps, and a pixel-level seam test makes sure the two overlays meet exactly.
- A hidden picture that stays hidden. A two-colour heart looked fine in tests but revealed nothing: each chat already "saw" its half. We switched to seam-split words and locked the last layer of detail until both sides are ready.
- The real broadcast is not a screenshot. A 10-letter channel name got cut off, the score bug read
READY READY READYduring the reveal, and the labels were too small at stream resolution. None of that showed up in headless tests; all of it showed up live. - Designing for someone else's stream. The overlay sits on top of any broadcast, so the chrome had to stay quiet and let the cards be the only loud thing.
Accomplishments that we're proud of
- It works live on Twitch: two real channels streaming from OBS at the same time, real chats, the bot posting in both, the wave crossing from one broadcast into the other — it's all in the video.
- Codex didn't just write code: it set the rules, reviewed itself, redesigned the product, critiqued its own screenshots, and fixed bugs that only a real stream could find.
- Privacy by design: lurkers stay anonymous; nothing from chat is ever rendered.
- Anyone can try it in one command, without a Twitch account.
What we learned
- Write the agent's rules before the features.
AGENTS.mdand the skills made every later Codex session safer and faster: the same hard rules caught regressions in review, in live testing and in the redesign. - Test on the real broadcast. Three real defects were invisible in 340 automated tests and obvious on stream within minutes.
- Count people, not messages. It keeps the stunt fair, spam-proof, and lets a small channel stunt with a big one.
What's next for Crossover Stunt
- A first party with real communities on both sides (so far we've tested with our two channels and one viewer account, plus simulated crowds up to 3,000 per side).
- A hosted version: paste two overlay URLs, no Node or tunnel.
- Three-way stunts and a
!stuntcommand for mods. - A quorum preview before Call, and measuring real OBS performance under big crowds.
Built With
- github
- gpt-6.1
- html5
- javascript
- node.js
- obs-studio
- openai-codex
- playwright
- pnpm
- prettier
- twitch
- twitch-eventsub
- twitch-helix
- typescript
- vitest
- web-audio-api
- websockets
Log in or sign up for Devpost to join the conversation.