Static Radio
A radio-style mobile app that plays a continuous, synced stream of podcast content across themed channels. Every listener hears the same thing at the same time — like real radio, but built from open podcasts.
Problem
Podcast apps are libraries — endless choice, no shared moment. Modern radio has lost its character to algorithm-shaped sameness and stadium-scale advertising. There’s a gulf between “I want to put something on” and “I want to choose between 73 million episodes.”
Insight
The thing real radio gets right is everyone hearing the same thing at the same second. That’s what makes radio feel social even when you’re alone. If we could rebuild that property — but source the content from the open podcast ecosystem rather than commercial broadcasters — we’d have something neither radio nor podcast apps can offer.
Solution
A small Flutter app that lands on a synchronized stream. The schedule is a flat array of episodes per
channel with fixed durations. The client computes position = (now − dailyEpochUtc) % loopDuration
and seeks into the episode at that offset. Nothing on the client is randomized — variety comes from the
schedule itself regenerating daily.
Eight channels
Each with its own scoring weights, palette, and audience.
Earth
Ambient field recordings, birdsong, rain, soundscapes.
Work
Lo-fi beats, ambient focus, white noise.
Learn
History, science, philosophy, documentary.
Weird
Paranormal, UFOs, cryptids, fringe science.
Unite
Coalition, solidarity, labor, mutual aid, cooperatives, abolition.
Make
DIY, woodworking, electronics, craft.
SHEILA B
WFMU archive — Sophisticated Boom Boom.
Sleep
Sleep stories, yoga nidra, brown noise.
The invariant
Everyone hears the same thing at the same time.
The single most important property of Static Radio is synchronized playback across all listeners. Two phones opening the app at 9:00:00 UTC on Monday must hear the exact same audio frame on the same channel. This is what makes it feel like radio instead of a podcast app.
Client-side variety would break the invariant. Variety comes from the schedule itself regenerating daily — driven by a deterministic seed keyed on the target date, with three independent rotation points (feed shuffle, per-feed episode selection, curated feed rotation) keeping every listener in sync while still producing a different program every day.
position = (now − dailyEpochUtc) % loopDuration. No randomness on the client. Variety comes from the schedule regenerating daily.How it works
- The pipeline discovers podcast episodes via PodcastIndex, scores and classifies them into channels, builds a 24-hour loop per channel, validates all audio URLs, injects bulletin ads, and publishes
schedule.jsonto Cloudflare R2. - The mobile app fetches that JSON and computes playback position from wall-clock time. Every listener lands on the same episode at the same second.
- The admin console manages the full operational surface: bulletin ad review, channel curation, content rules, curated feeds, schedule builds, and fleet rotation — all from a single panel backed by D1 + R2.
What I designed
Wheel interaction. Drag maps directly from wheel angle to station travel; release uses magnet/snap to land on a station. Haptics: micro-ticks during movement, snap thud on settle.
Hero image. Riso-printed look via a custom _RisoPrintedImage widget plus
palette-derived drum layers per channel. Crossfades between left/right category pair during scrubbing.
Mute behavior. Center mute glyph rendered independently from the hero image. Hero desaturates when muted; the mute glyph and favorite heart stay colored. Press/membrane animation: body depresses and compresses, wheel stays rigid.
Fallback audio chain. For bulletin episodes: primary URL → fallback URL (a static
ad.mp3 on R2 so all devices try the same thing and stay synced) → generated pleasant noise
(brownian + white + AC hum blend, looped) as a last resort.
Get it
Static Radio is shipping. App Store and Play Store links will be added shortly.