99 Francs
sales@99francs.agency

HQ Paphos, Cyprus · worldwide

Case study · Our own product

Meridian Radio: a night planet lit only by radio, and a horizon that turns into a dial.

Spin the globe, aim at a country and dive in: the edge of the planet bends into an analog tuner with that country’s stations laid out from west to east. 40,000+ live stations from 200+ countries, built natively for iPhone, Apple Watch, Mac and Android, plus a web player. The web player is live; the apps are in review on the App Store and Google Play.

Meridian Radio on three iPhones — the night globe over Europe, the Hologram tuner in Japan and the Instrument tuner in Germany — with the Apple Watch tuner and the Mac menu-bar player in front
ProductOur own product · built and run by 99 FrancsCyprus
PlatformsiPhone, Apple Watch, Mac, Android, web
StatusIn review · App Store and Google Play · web player live
BuiltOctober 2026
StackSwiftUI + Metal, Kotlin + Compose, Astro + WebGL2
Languages8 in the apps and on the site
Direct answer

Our own world radio app — one catalog, five native surfaces, designed and built by 99 Francs.

Meridian Radio is a SwiftUI and Metal app for iPhone with widgets, an Apple Watch app and a Mac menu-bar app, a Kotlin and Jetpack Compose port for Android, and an Astro and WebGL2 web player. All of them read one station catalog of 40,000+ stations from 200+ countries. The web player is live; the apps are in review on the App Store and Google Play.

Why we built it

World radio, as an instrument.

Most radio apps are long lists of logos. We wanted the feeling of turning a real receiver, except that the band spans the planet — and a product of our own that pushes design, graphics and audio as far as a native app can go.

The horizon becomes the dial

Planet and tuner share one circle. The dive interpolates the globe's outline on screen into the dial's circle, so the edge of the Earth literally turns into the scale.

Geography is the frequency

Stations sit on the dial from west to east, or north to south in tall countries. The readout under the needle is a live latitude, and every station shows its city's local time.

A planet lit only by radio

There are no city lights on the globe. Every glowing point is a real station, drawn from one density texture, and the stations of the country under the reticle pulse.

Meridian Radio orbit view on iPhone: a dark globe lit only by station dots, Germany under the reticle with 4,397 stations on air and a Tune in button
Meridian Radio tuner on iPhone: the horizon has become an engraved dial with German stations, Mangoradio under the needle, live, with its local time
Orbit → dive → tuner

Aim at a country. The planet becomes the radio.

The globe is ray-traced in a single fragment shader. Tap Tune in and the camera dives: the planet’s circle morphs into the dial’s circle, the scale is engraved along the horizon, static rises and the first station locks. Turn the heavy knob and stations click into place with haptic detents; between them you hear synthesized static, as on a real receiver.

  • Drag the globe → the country under the reticle lights up
  • Tune in → the horizon becomes the dial, west to east
  • Turn the knob → detents, static, then the station
How it was built

One catalog, five surfaces.

One team did all of it: the concept and design, five native surfaces, the shared catalog and tooling, the store listings and the web player.

01

Concept and prototype

Orbit, dive and tuner as one continuous move, in an “Instrument” style: engraved scales, warm monochrome, one signal orange, a heavy knob with haptic detents.

02

The catalog

The full Radio Browser directory, geocoded against GeoNames, with brands de-duplicated and names cleaned. One stations.json feeds every app; the watch and the web get their own trimmed copies.

03

iPhone app

SwiftUI and a Metal globe for iOS 26, background audio, Now Playing, AlarmKit wake-up alarm, sleep timer, Home Screen and Lock Screen widgets, and 8 languages switched inside the app.

04

Android port

Kotlin and Jetpack Compose, one to one with the iPhone: the same shader in OpenGL ES 3, the same dial physics and unit tests, Media3 playback and a home-screen widget.

05

Watch, Mac and web

An Apple Watch app with complications that syncs with the phone, a Mac menu-bar app, and a web player in Astro and WebGL2 on Cloudflare Pages that doubles as the landing site.

06

Store listings and review

Keyword research per storefront, listings in 10 locales on both stores, screenshot sets for iPhone, Apple Watch, Mac and Google Play. All of it is now in review.

Same product, native on each platform

iPhone and Android, mapped one to one.

The Android app is a port, not a rewrite of the idea: the same shader, the same physics with the same unit tests, the same names. Where the platforms differ, each gets its own native API.

Planet and dive

iPhone · Metal: a ray-traced orthographic globe in one fragment shader

Android · OpenGL ES 3 GLSurfaceView, the same shader ported to GLSL

Camera, dial physics, layout, switching

iPhone · Swift, pure logic, unit-tested

Android · Kotlin, a line-for-line port with the same unit tests

Playback

iPhone · AVPlayer, background audio, Now Playing and lock screen

Android · Media3 ExoPlayer and MediaSessionService, with notification and lock screen

Static between stations

iPhone · An AVAudioEngine source node: filtered noise, crackle, a heterodyne whistle

Android · AudioTrack streaming the same synthesis

Screens

iPhone · SwiftUI: splash, orbit, tuner, sheets

Android · Jetpack Compose: the same screens, a Canvas dial, a metal knob

Wake-up alarm

iPhone · AlarmKit system alarm with a “Play radio” button

Android · AlarmManager.setAlarmClock and a service that starts the station itself

Haptics

iPhone · Core Haptics and UIImpactFeedback

Android · VibrationEffect primitives: tick, click, heavy click

Glass controls

iPhone · iOS 26 Liquid Glass

Android · RenderEffect blur on Android 12+, a translucent fallback below

8 languages

iPhone · L10n.swift, generated from one strings.json

Android · L10n.kt, generated from the same file

Data

iPhone · The bundled station catalog, Natural Earth borders

Android · The same catalog and textures, copied in at build time

Three receivers

The same dial, three receivers, two themes.

Instrument is engraved metal and one signal orange; Hologram is a cyan HUD; Chrome is a liquid-metal knob. Each works in the dark and light themes. Around the tuner: a filter that lights up only the stations in a language or genre, search and favourites, and a sleep timer and wake-up alarm set on mini dials.

Meridian Radio tuner in the Instrument skin: Mangoradio live from Rheinland-Pfalz, Germany, on an engraved dial with a brushed-metal knob
Instrument
Meridian Radio tuner in the Hologram skin: Jazz Sakura in Japan on a cyan dial with a glowing knob
Hologram
Meridian Radio tuner in the Chrome skin and light theme: Rai Radio 1 in Lazio, Italy, with a violet needle
Chrome · light
Meridian Radio filter sheet on iPhone: Spanish selected, showing 3,499 stations in 58 countries, with genre and language counts
Meridian Radio search and favourites sheet on iPhone over the BBC World Service, with popular stations in the United Kingdom
Meridian Radio sleep timer set to 30 minutes and a wake-up alarm at 07:30, both set on engraved mini dials
Beyond the phone

In the menu bar, on the wrist, in the browser.

On the Mac, a small instrument panel drops from the menu bar and you tune by scrolling across the dial. The watch keeps favourites, the last station and the language in step with the iPhone, with complications on the watch face. The web player runs the same globe shader in WebGL2.

Meridian Radio Mac menu-bar player in the dark theme: Antena 1 from Portugal on air, a tuning dial, playback controls, the station list and sleep timer presets
Mac menu-bar app · dark
Meridian Radio Mac menu-bar player in the light theme with the Portuguese station list
Mac menu-bar app · light
Meridian Radio on Apple Watch: the tuner dial with French stations, EuroDance 90 radio live, with favourite and pause buttons
Apple Watch app
Meridian Radio Apple Watch complications: FIP live from Paris and Radio Swiss Jazz from Basel, each with a small dial
Watch complications
Hard parts

What a radio on a globe hides.

None of these show up in a design file. Each surfaced on a real device or a real stream, and each is now something we plan for in client apps from the start.

A needle that moves too fast

Switching stations while the dial was still spinning could leave the old station playing. The player now switches only after the needle has rested on a station for 0.18 seconds.

Dead streams

Community catalogs carry streams that no longer answer. An 8-second start watchdog skips them, and between stations the static is synthesized live, mixed by signal strength.

A globe that never idles

The planet renders every frame, so Compose's own test rule never sees the UI settle. Android UI tests run on UiAutomator instead, with the logic covered by JVM unit tests.

Browsers can't play every stream

Many stations still broadcast over plain HTTP, which a secure web page cannot play. The web catalog keeps only HTTPS streams, sharded by country; the apps carry the full list.

A widget with no app running

On Android the home-screen widget can start playback after the app process has died, from the stream it saved. On iPhone, widget buttons are playback intents wired into the app's player.

Borders are a decision

Borders come from Natural Earth's Ukrainian worldview, so Ukraine is drawn in its 1991 borders, Crimea included. No stations located in Russia or occupied territories are in the catalog.

Where it stands

Live on the web, in review on both stores.

The web player is live in 8 languages. The iPhone app with its Apple Watch companion and the Mac app share one App Store record and are in review, as is the Android app on Google Play. Free, with no account.

5

surfaces from one catalog

iPhone with widgets, Apple Watch with complications, a Mac menu-bar app, Android with a home-screen widget, and a web player.

40,000+

stations from 200+ countries

From the open Radio Browser directory, geocoded city by city and placed on each country's dial from west to east.

8

languages in the apps and on the site

English, Italian, Spanish, Portuguese, German, Russian, Ukrainian and Chinese, with store listings in 10 locales.

Concept → native builds → store listings → web

Need an app that people remember after the first touch?

We design the product and build it natively for iPhone and Android, with GPU graphics, audio, widgets, watch and desktop companions and store listings around it — the way we build our own.

SwiftUI · Metal · Kotlin · Jetpack Compose · OpenGL ES · WebGL2
Case study FAQ

Questions about Meridian Radio.

A free world radio app. You start on a night globe lit only by radio stations, aim at a country and dive in, and the planet's horizon turns into an analog tuner dial with that country's stations laid out from west to east. It plays 40,000+ live stations from 200+ countries, with no account.
No. It is our own product. 99 Francs designed it and built the iPhone, Apple Watch, Mac and Android apps, the web player, the catalog tooling and the store listings, and runs it. We build products for ourselves so we know first-hand what it takes to ship and maintain an app.
In a browser, yes: the web player at meridian-radio.pages.dev is live. The iPhone app with its Apple Watch companion and the Mac menu-bar app are in App Store review, and the Android app is in Google Play review.
Swift and SwiftUI with a Metal globe shader, AVFoundation, AlarmKit and WidgetKit on iPhone, Apple Watch and Mac, generated with XcodeGen. Kotlin and Jetpack Compose with OpenGL ES 3 and Media3 on Android. Astro and WebGL2 on Cloudflare Pages for the web player. Python tooling builds the shared station catalog, the border textures and the strings for all of them.
The product is a real-time GPU globe, a haptic knob, background audio, a system alarm, widgets, a watch and a menu bar. Each of those is a native API, so we built each platform natively and kept the shared parts, the catalog, the shader and the strings, in one place.

Yes. The same team designs the product, builds native iOS and Android apps with shaders, audio, widgets and watch or desktop companions, and prepares the store listings. See mobile app design, iOS app development and Android app development.