We Drew This

Stream Journal

Loading stream history...

Dev Log

Week 9: Hardening the Daily Pipeline April 13 – 16, 2026
The daily vote generator went live this week — and immediately taught us lessons about production reliability. An image format mismatch (FLUX sometimes returns JPEG despite a .png extension) crashed the title generation step, and EventBridge helpfully retried the Lambda three times, creating three orphan artworks at $0.05 each. We added magic-byte detection for image formats, built an idempotency guard that stores the generated filename in DynamoDB so retries reuse the existing image, and wired up automatic failure cleanup that moves orphans to a failed/ folder with metadata.

On the community side: voters can now change their votes until the poll closes at 6 PM, we launched streak-based emoji unlocks, recovery codes for identity restoration, and optional Twitch account linking. Theme weeks let us run parallel polls with curated aesthetics. The gallery got a "Lost Art" page for browsing rejected and failed artwork — with a rescue button to pull favorites back into the gallery. We also built a protected originals/ archive on S3 with a deny-delete bucket policy, because unwatermarked source images are too valuable to lose.
Week 8: Daily Voting Goes Live April 6 – 12, 2026
The biggest feature of the project launched: daily web voting at wedrewthis.com/vote. Instead of requiring a live Twitch stream, anyone can vote on the next artwork 24/7. The architecture uses two Lambda functions (vote API + generator), three DynamoDB tables, and an EventBridge schedule that fires at 6:01 PM Pacific daily. The generator tallies votes, generates artwork via Claude + FLUX, watermarks it, creates Printify products, and sets up the next poll — all in under 90 seconds.

We also added a favorites system to the gallery (heart button with a Lambda-backed DynamoDB counter and IP deduplication), an offline page for the stream overlay that detects real client IPs through nginx proxying, and a profanity filter for voter nicknames that handles prefix/suffix matching to catch creative circumventions while allowing legitimate words.
Week 7: The AI Narrator March 30 – April 5, 2026
The stream got a voice. An AI narrator (Claude for script, ElevenLabs for speech) now commentates during idle moments and active rounds. The tricky part was audio routing: PulseAudio virtual sinks mix the narrator with background music, and we learned the hard way that ffmpeg device arguments are unreliable — the PULSE_SINK environment variable is the only reliable way to route audio to the right sink.

We added automatic scene switching that detects real viewers (filtering out the broadcaster's own accounts via the Twitch chatters API) and cycles between gallery and instruction cards when nobody's watching. Vote sequences expanded from 5 to 12 templates (Moody, Cinematic, Surreal, Retro, etc.) loaded from a JSON config. Title generation now sends the actual image to Claude Vision, producing much better titles than text-only prompting. And the deploy pipeline got a safety check: GitHub Actions skips the EC2 restart if an RTMP stream is active.
Week 6: Viewer Engagement March 23 – 29, 2026
The stream started tracking individual voters. A leaderboard system records per-viewer stats — rounds participated, voting streaks, milestones at 5/10/25/50 rounds. Chat commands (!leaderboard, !stats) and a dedicated overlay scene show rankings. The gallery website got contributor filtering so viewers can find artworks they helped create.

Music voting arrived via !changemusic — a two-phase vote where viewers pick from web radio presets (Lofi Girl, SomaFM, Jazz24). Background music streams through PulseAudio via Streamlink + FFmpeg, routed to a virtual sink that the RTMP pipeline mixes with the overlay audio.
Week 5: Print-on-Demand & Social March 14 – 22, 2026
Every artwork now gets a Printify store automatically — 10 product types (tees, posters, mugs, stickers, puzzles, magnets) created via the Printify API. The publish flow was full of surprises: the visible field means dashboard visibility, not storefront presence (you need to check external.handle), variant IDs must come from the product itself not the catalog, and rate limits kick in around 6-7 calls per minute.

Style-matched watermarks replaced the plain text overlay. The pipeline uses Claude to craft a style prompt matching the artwork's aesthetic, FLUX Fill Pro to inpaint a signature that blends naturally, and Claude Vision to validate the result. A Pillow text fallback catches the rare cases where inpainting fails. Social media auto-posting shipped via Claude-generated captions, though Instagram's spam detection immediately flagged the automated posts.
Week 4: Gallery & CloudFront March 7 – 13, 2026
The first live stream happened on March 7. The gallery website moved from the EC2 instance to S3 + CloudFront — always-on, pennies per month, with 30-second cache TTL on the gallery manifest and 7-day caching on images. Social share cards use a CloudFront Function that intercepts /art/{id} URLs and returns OpenGraph meta tags (with a JS redirect instead of meta refresh, because Facebook follows meta refresh and misses the og: tags).

The gallery got progressively richer: search, tag filtering by vote categories, sort modes (newest/oldest/A-Z/most-loved), a fullscreen slideshow, deep-linking to individual artworks, and a responsive carousel on the homepage that cycles through the collection with Ken Burns panning.
Week 3: Streaming Pipeline February 28 – March 6, 2026
Getting video to Twitch was the hardest engineering problem. The first attempt used Playwright screenshots piped to FFmpeg — too slow. Then raw x11grab from Xvfb, which worked but was software-rendered and CPU-bound. The breakthrough: switching from Xvfb to real Xorg with the NVIDIA driver on a GPU instance. On a g4dn.xlarge (Tesla T4), the stream runs at smooth 30fps/4500kbps with ~40% GPU utilization.

The admin panel went from zero to full remote control: a Python HTTP server with session auth, REST endpoints for stream start/stop/pause, SSE for live state updates, and a dark-themed dashboard. A state machine (StreamController) manages the round lifecycle with interruptible sleep and a command queue, so the admin can pause mid-round or skip ahead.
Week 2: Chat Voting & Deployment February 21 – 27, 2026
Twitch Polls require Affiliate status, which we didn't have. The solution: IRC-based chat voting using Python's stdlib ssl + socket + select (no external dependencies). Viewers type a number in chat, the bot tallies votes in real time, and results appear on the overlay with animated tally bars.

The project got its first deployment infrastructure: nginx reverse proxy with Let's Encrypt SSL, a systemd service for headless operation, and the beginnings of what would become the CI/CD pipeline. Twitch OAuth gained token persistence and automatic refresh so the stream doesn't need manual re-auth after restarts.
Week 1: The Prototype February 14 – 20, 2026
The idea was simple: what if a crowd voted on art elements and an AI generated the result? The first prototype stitched together Claude (for crafting image prompts from voted categories), FLUX 2 Dev on Replicate (for image generation), and a browser-source overlay for OBS. The core loop — generate options, collect votes, craft prompt, generate image, display — worked on day one.

The cascading vote system emerged immediately: each category's options are informed by the previous winners, so "Cosmic Jellyfish" as a subject leads to space-themed action options rather than generic ones. This turned out to be the key design decision that makes the artwork feel cohesive instead of random. The overlay went through rapid iteration: numbered option pills, Ken Burns animation during voting, typewriter effects for titles, and a static display phase to let viewers appreciate each piece.