mHub

Any idea. Every screen.

mHub is an open platform that turns folders of simple files and ordinary websites into apps for phones, TVs and desktops. You do not need to be a programmer: if you can describe what you want, an AI can build it, and mHub gives it a place to run.

Dyscover on a TV: a featured DW show above rows of documentaries and business videos, with the addon's catalogs along the top.
Dyscover, an mHub app, on a TV. Everything on this screen comes from one addon: DW.
The concept

One platform, three parts.

mHub is not one app. It is three parts that fit together, and every one of them is open. Two are foundations: a content format and a browser API. The third is the apps, and each of them stands on one foundation or both.

01

The apps

What you actually use. Dyscover turns addons into one browsable screen, and other apps each take one idea to every screen in the house. All of them are web apps: nothing to install. See the apps

02

The content: addons

An addon is a source of content: films, radio stations, podcasts, courses. Under the hood it is a folder of small text files on any web host, described by the Addon Protocol v2. An AI can write one for you. See the protocol

03

The powers: window.mhub

Open a normal website inside an mHub app and it can do things a browser never allows: read data from anywhere, survive a dead domain, live on your TV. One namespace, one script tag: the mHub Browser API. See the API

Part one · The apps

Dyscover, and what is built beside it.

Dyscover stands on both foundations; the apps beside it show how far one foundation alone carries. All of them are live.

Dyscover

Give Dyscover addons and it turns them into one browsable screen: every catalog your addons expose, search across all of them, a library, a player that resumes where you left off. It is one web app that runs on phones, TVs and desktops alike, and handles touch, remote control and pointer itself.

It stands on both foundations: addons bring the content, and inside an mHub browser the Browser API adds the powers a plain page never has. You can even mount it on a page of your own, with your addons and your name on it: one HTML file.

Dyscover on a phone: a featured DW show with details and my-list buttons above a row of live TV channels. The DW addon in Dyscover on a phone: featured news video and a scrollable list of clips.

Waves

Radio stations, podcasts and free audiobooks as one app. Waves is one HTML file over the same Dyscover build: five audio addons, a teal accent, and addonManager: "fixed", so the sources are set and the user only switches them on and off. View source on it: the page is the whole tutorial.

Waves: a podcast hero above rows of SomaFM radio stations, with a teal wave logo in the sidebar.
Waves: SomaFM, Radio Browser, podcasts and audiobooks, teal on dark. One HTML file on Dyscover.

Junior

Kids TV. One addon, bright colours, German from the first screen (locale: "de"), and addonManager: "hidden": nothing to misconfigure from the couch. Also one HTML file over the Dyscover build.

Junior: a KiKA animation hero above rows of kids shows, in German, with a yellow star logo in the sidebar.
Junior: the KiKA addon and nothing else, with a star on the door.

Mediathek

The addon is the data; what someone builds on top of it is the app. Mediathek is one HTML file straight on the ard-mediathek addon, no Dyscover underneath: rows, search, series with their episodes, subtitles, and a player that remembers where you stopped. The addon does the fetching, the page does the looks.

Mediathek: rows of ARD videos and series with titles, dates and running times, and a search field.
Mediathek, one HTML file over one addon, with nothing of its own to host.

Glance

The other foundation on its own: Glance uses no addons at all. One HTML file on the Browser API, pulling live weather, headlines, market prices and the status of your own servers onto one calm screen. In a plain browser it degrades gracefully; inside an mHub app every tile wakes up.

Glance: clock, weather, market prices and news headlines as calm tiles on one screen.
Glance, one HTML file, pulling live weather, headlines and prices.
Part one · Make Dyscover yours

Your own app is one HTML file.

Waves and Junior are exactly this: load the Dyscover build, give it an element, call mount. This file, on any static host, is a finished app with your addons, your name and your colours, and it follows Dyscover releases by itself. No build step, no server code, no account.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport"
  content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=no">
<title>My App</title>
<link rel="stylesheet" href="https://dyscover.mhub.mx/latest/style.css">
<script type="importmap">
{ "imports": { "hls.js": "https://dyscover.mhub.mx/latest/hls.mjs" } }
</script>
</head>
<body>
<div id="app"></div>
<script type="module">
  import { mount } from "https://dyscover.mhub.mx/latest/app.js";
  mount({
    addons: ["https://www.mhub.mx/dw"],
    brand: { name: "My App", colors: { accent: "#00AAFF" } },
  });
</script>
</body>
</html>

An addon is its manifest URL. The ones hosted here are listed on the addon index, and an AI can build you a new one.

Every mount option

Everything is optional. With no options at all you get Dyscover as it runs on its own domain: no addons installed yet, the whole addon system open, the Dyscover mark.

addons

The sources the page ships with. A URL, or { url, enabled } to ship one switched off.

addons: [
  "https://www.mhub.mx/dw",
  "https://www.mhub.mx/kika",
]
// ship one switched off:
{ url, enabled: false }

brand

name, logo (sidebar), icon (favicon) and four colour slots: accent, primary, bg, text. The rest of the palette is derived, so two colours restyle the whole app.

brand: {
  name: "Waves",
  logo: "/logo.svg",
  colors: { accent: "#2EC4B6" },
}

locale

A string is the start language. An array is the languages on offer; a single entry hides the language row. Unset means the browser language.

locale: "de"
// or the offer:
locale: ["de", "en"]

addonManager

How much of the addon system the user gets to see. Three modes:

"open"    the user adds, removes and switches sources; your list seeds once,
          the user's decisions win from then on
"fixed"   your list and nothing else; the user only switches sources on and off
"hidden"  no addon screen at all; enabled is the state, on every boot

A line { id: "arte", enabled: true } in addons switches one addon a source brought: the entry of a repository you want running without spelling out its address.

el

Where to render: a selector or an element. The default is #app, so most pages never set it.

el: "#app"

settings + startRoute

settings: false removes the settings screen and its menu entry. startRoute picks the first screen.

settings: false,
startRoute: "channels"

links

Tiles for the mHub browser home screen. Unset, the host gets one tile with your brand's name on it.

links: [
  { id, name, icon, url }]

mount() returns

{ el, navigate, unmount }: the element it rendered into, a way to switch screens from your own code, and a clean teardown.

From here, or from your own host

The build is served from dyscover.mhub.mx with open CORS, so the snippet above works from any origin as it stands.

latest, or a pinned version

/latest/ is a short redirect onto the current version folder, so a page that loads it is up to date minutes after a release. To freeze your app instead, put a version in the path: those folders never change and cache for a year. latest.json names the current version.

/latest/app.js    follows releases
/v/0.1.0/app.js   frozen forever

The version folder

Hosting the files yourself works too. A version is four files: download them, put them next to your page, change the three URLs in the snippet to relative ones. Any static host works; when it updates is then yours to decide.

/v/0.1.0/app.js      the app, one module
/v/0.1.0/style.css   the look
/v/0.1.0/hls.mjs     the stream engine
/v/0.1.0/index.html  mount() with no options

Where it runs

Any modern browser. The addons hosted on mhub.mx answer with CORS headers, so a plain browser can browse them; what a stream allows is up to the addon's source. Inside an mHub browser the same page gets the full Browser API: cross-origin fetching, streams that need their own headers, storage that follows the site.

Part two · The Addon Protocol v2

An addon is a folder of JSON files.

An addon is a source of content: films, radio stations, podcasts, recipes, courses. Put the folder anywhere on the web, add its address in an app, and everything in it appears there, browsable. Version 2 of the protocol needs no server: every endpoint can be a static file on any CDN. Every existing v1 addon keeps working; the apps translate between the two, and v1 stays supported.

Static-first

All endpoints are GET, all cacheable, all hostable as plain files. One optional POST for the task system.

/mhub-addon.json
/catalog/{type}/{catalogId}.json
/item/{type}/{id}.json
/source/{type}/{id}.json

Composable

Catalogs, item details, sources, resolvers and subtitles are separate resources. One addon can provide all of them or just one.

"resources": ["catalog",
  "item", "source",
  "resolve", "subtitle"]

Client-fetch tasks

An endpoint can answer with a task instead of data. The app fetches with the user's own IP, so a static addon works with geo-blocked APIs.

// addon stays static,
// the client does the trip

mhub-addon.json

A minimal addon is one manifest and one catalog file. Upload both to any static host and it works. The spec is OpenAPI 3.1 with generated TypeScript types and a zero-dependency client library, MIT licensed, on GitHub.

{ "id": "my-movies", "name": "My Movies", "specVersion": 2,
  "resources": ["catalog"], "types": ["video"],
  "catalogs": [{ "id": "all", "name": "All", "type": "video" }] }
Part two · Build with AI

Describe it. An AI builds it.

The whole addon format fits into a single prompt, and you never have to read it. Copy the prompt, add your idea, and the AI answers with a folder of files. Upload them anywhere and your addon is live.

01

Copy the prompt

It points the AI at the spec. Works with any assistant that can read links, like ChatGPT or Claude.

02

Add your idea

"My favorite radio stations." "Every film by one director." "The public lectures of my university." Anything with a list.

03

Upload the files

Any static host works, GitHub Pages is free. Add the address in an mHub app and browse your own addon.

Read the mHub Addon Protocol v2 spec at
https://raw.githubusercontent.com/mediahubmx/protocol/main/openapi.yaml
and build an addon for me. An addon is a folder of static JSON files,
ready to upload to any web host. Answer with every file: its full path,
then its complete content.

My addon: [describe your idea here]

If your assistant cannot open links, paste the spec file into the chat instead. The spec and complete example addons live on GitHub.

Part three · The mHub Browser API

What your site can do inside mHub

Everything lives under one namespace: window.mhub, and every host serves the full core. Feature-detect the namespace once, then just call it. No SDK, no build step, no account: one script tag is the whole setup, and self-hosting it is fine.

<script src="https://mhub.mx/mhub.js"></script>
Checking this browser…
Host
Device
Capabilities

The API is built and documented, and it arrives with the next release of the apps. Write against it today and your page keeps working either way: where no host is present, window.mhub is simply absent and your site stays an ordinary website.

mhub.fetch

Fetch anything. No CORS, and request headers the browser normally reserves for itself.

// cross-origin, readable
const r = await mhub.fetch(url);

mhub.openStream

Some media needs its own request headers to play. One call, and the host picks the right route on every platform.

const s = await mhub.openStream(
  { url, headers });
video.src = s.url;

mhub.storage

Key/value storage that follows your site, not the domain it happens to run on. No prompt, no setup.

await mhub.storage.set(k, v);

mhub-site.json

One domain down, your site still loads. Serve one small file on every domain; the browser finds it, verifies your mirrors and fails over by itself. No code.

{ "id": "mysite",
  "endpoints": [
    "https://a.example",
    "https://b.example" ] }

mhub.setLinks

A tile on the browser home screen. The way back to your site, surviving between visits.

mhub.setLinks([
  { id, name, icon, url }]);

mhub.setSearch

The address bar becomes your site's search. Queries and suggestions go straight to your page.

mhub.setSearch({ placeholder,
  onQuery, onSuggest });

mhub.device + capabilities

Know where you run and what the host can do, from phone to TV, before first paint.

if (mhub.device.isTV) tvUi();

…and the app declarations

A page that runs as an app tells the host what it handles itself: its own back navigation (setBackHandler), edge-to-edge layout (setEdgeToEdge), a full-screen player (setImmersive), and the door out (exit); a meta tag in the HTML says it is an app built for the remote. Every member, with the permission model and the mirror system, is in the API reference.

mhub.setBackHandler(depth);
mhub.setImmersive(true);
<meta name="mhub" content="app dpad">
Part three · Ideas

Not just media.

The obvious use is a media library on your TV. But the powers underneath are general, and most of these are impossible as a normal website. A few things a single web page can be inside mHub:

A news reader

Pull any feed straight from its source. Normal browsers block that; inside mHub it just works. Your reading list follows you, and it reads well from the couch.

A family screen

Weather, headlines and the price of things you care about, as one calm screen on the TV. We built this one; it is the Glance screenshot further up, and it runs live.

A home control panel

Talk to the devices in your own network: lights, NAS, printer, router. Browsers refuse local requests like that; the mHub app makes them for you.

A podcast player

Fetch feeds, play episodes, resume where you stopped. One page, no server, no app store.

A price watcher

Check shops for prices and availability, keep a watchlist. The page asks; you see the answer on any screen.

An archive browser

A friendly face for open archives like Archive.org or Project Gutenberg. Browse, search and read them like an app.

Build something. Big or small.

The API reference covers every member, the permission model, and the mirror system. The protocol spec ships with complete example addons you can copy.