-
-
The signed-out story picker offers camera-free rehearsal before a performer connects Twitch.
-
The returning umbrella lands in the held palm, with its coral patch and wetness intact.
-
Real Twitch chat and the simultaneous stage: the umbrella crosses after the acceptance vote.
-
Illustrated rehearsal: stamp a parcel, pass it through the portal, and open a pocket of stars.
Inspiration
I wanted to give a Twitch viewer a different kind of moment: "The streamer is standing in the rain because we borrowed their umbrella. Should we give it back?"
That became PORTAL STAGE, a little live theater where your room opens onto an illustrated Audience Room. You perform on camera. Chat helps decide the story. A patched umbrella can follow your hand, cross the portal when you offer it, and return to your waiting palm.
You offer shelter, lose it, meet a tiny visitor, and decide whether to share. The choices are authored. The hesitation, reactions, and comedy belong to the performer and their community.
What it does
The first episode is Borrowed Weather. A streamer steps into a warm, paper-theater world with a coral-patched umbrella. Twitch chat chooses gentle weather or a storm. The performer opens their palm toward the portal and holds it to offer the umbrella. Chat can accept it into the Audience Room or ask it to wait.
On the other side, chat names a little creature and shapes its mood. In my demo, the visitor becomes Sprig, curious enough to emerge beneath the borrowed shelter while I am still in the rain. Chat then chooses to give the umbrella back. I hold out my hand, catch it, and lift it. Its patch and wetness survive the trip. The final choice brings Sprig and the umbrella together in a shared shelter.
The server records the new owner before the crossing begins. An interrupted animation cannot create a second umbrella or undo a completed handoff.
A second episode, Midnight Parcel, turns that same interaction into a delivery. You stamp a package, send it through the portal, and reveal either a pocket of stars or a midnight garden in the receiving room. Its tag and handling marks stay with it. The final choice decides which room keeps the gift.
Built for the performance
The stage stays central. Warm light, theatrical curtains, textured scenery, and a restrained control panel make it easy to see the story. Cue cards guide the director through each scene. Chat receives short, memorable commands such as !wild, !accept, and !giveback.
The streamer opens and closes each choice and controls when its result appears on stage. Each Twitch account gets one replaceable ballot per choice. An empty or tied result asks for an explicit Director's choice, so silence never pretends to be an audience decision.
Optional hand cues make the physical gesture part of the scene. A small gold ring shows the performer when a deliberate palm hold is ready. Button controls remain available. Camera preview, permission to appear on the stage, and permission to appear in a demo recording are separate decisions.
Both illustrated episodes can be rehearsed without an account or camera, giving visitors something to play immediately and streamers a place to learn the pacing.
How I built it with Codex
I used Codex throughout implementation and review, splitting work across the show protocol, stage interface, and media and gesture modules. I integrated them through browser tests, live Twitch checks, and physical webcam rehearsal.
One small bug could have broken the whole promise: real Twitch messages disappeared because their identifiers contained characters our filter rejected. Codex traced the failure, corrected the bounded identifier check, and added regression tests. The demo shows that development record and the repaired chat path.
The app uses Next.js, React, and TypeScript. Three.js renders a single canonical stage. Twitch OAuth and EventSub connect the host and deliver chat choices. LiveKit handles the consented media paths. MediaPipe tracks hand landmarks locally in the browser. Neon PostgreSQL stores the show and its prop ownership, while Vercel hosts the app and Workflow closes timed solo sessions durably.
Codex helped build the software; an authored show grammar governs the performance. That lets the streamer understand the available consequences and improvise around them.
Challenges and what I learned
A handoff has to feel convincing and remain correct when timing goes wrong. I separated durable ownership from presentation, so the crossing starts only after acceptance is committed, but still gets its full visible journey. One composed stage keeps the prop and performer aligned.
Actual rehearsal also caught a hand-tracking adapter treating an unavailable confidence field as zero. Fixing that was only the beginning. I needed deliberate holds, smoothing, a brief loss grace, and a return that targeted the receiving palm. A passing test cannot tell you whether catching an umbrella feels right. Performing the scene could.
What I am proud of
The deployed solo path connects real Twitch choices, my physical performance, and a complete little story. The release passed 537 tests, type checking, formatting, and a production build. The public MIT repository includes setup instructions and concrete development evidence.
The demo is a controlled test with me performing and another account I own supplying chat commands. Independent streamer sessions are next, along with broader camera and device trials. The invite-only Duet path needs further two-person testing before I would present it as proven.
Try it
Open PORTAL STAGE, enter Studio, choose Borrowed Weather, and select Start rehearsal. Open the curtain, open a weather choice, cast a labeled test ballot, and continue through the cue cards. Try Midnight Parcel for the second story.
Public demo · Open-source repository · Field guide · Codex development record
Built With
- codex
- eventsub
- livekit
- mediapipe
- neon
- next.js
- openai
- postgresql
- react
- three.js
- twitch
- typescript
- vercel
- vitest
- webgl
Log in or sign up for Devpost to join the conversation.