TV Browser+
Browsing the web with a TV remote is miserable. This makes any website usable from the sofa, and it hit the hardest wall of the project.
What it is
TV Browser+ is a module for TizenBrew, an open-source tool for Samsung TVs that injects scripts into web pages (it's also what powers ad-free YouTube on the TV). Our module is injected into every page you open and adds:
| Feature | How it works |
|---|---|
| Remote cursor | Arrows move a cursor that speeds up when held. OK clicks, CH▲▼ scroll, Back goes back. Red toggles the cursor, Green opens the start page. |
| Jump mode | Press Yellow and the arrows hop between links and buttons with a red highlight, starting at the link nearest the cursor. OK opens. |
| Phone pad | Scan the start page's QR: a touchpad (drag to move, tap to click, two fingers to scroll), a URL bar and a keyboard. |
| Text size | A− / 100% / A+ on the phone, remembered per site. |
| Direct link | The phone talks to the TV over Wi-Fi with WebRTC, with a cloud fallback. The phone shows "Direct · N ms" or "Internet · N ms". |
The cursor is a 30 px white ring with a red centre, on its own GPU layer and redrawn at most once per frame, so it stays smooth even on heavy pages.
The wall
The plan was to reuse the fast path from the phone remote: the phone talks to the TV's own server, about 10 ms away. It didn't work, and the reason is a browser security rule.
Almost every website is served over https. The TV's own server is plain http, on the TV itself. Browsers block a secure page from talking to an insecure local address (mixed content). Our injected script lives inside that secure page, so it can't reach http://127.0.0.1:8090. The launcher can, because it's a local app, not a website.
Version 1.2 fell back to the cloud relay: the start page makes its own room, and the phone and the page meet there. It works everywhere, but it's back to ~80 ms.
The way around it: WebRTC
WebRTC is how video calls connect two devices directly. It's allowed from secure pages, and once connected, the data goes straight across the Wi-Fi. The cloud is only needed for the introduction.
Start page ── makes its own room ──▶ QR = https://<relay>/r/<room>
Phone ◀══ wss ══▶ cloud room ◀══ wss ══▶ page script introduction + fallback, ~80 ms
Phone ◀════ WebRTC data channels, over Wi-Fi ════▶ page direct
- The two sides swap connection details (
{t:'rtc', sdp|ice}) through the cloud room, using public STUN servers. - Then they open two data channels: "fast", unordered and unreliable, for cursor moves where only the latest one matters, and "ctl", reliable, for clicks, text and navigation.
- The phone pings every 2 seconds, and the TV answers on whichever path the ping arrived on. That drives the live delay meter.
- The room follows you from site to site in
window.name, so you don't rescan the QR on every page.
Honest status: in a two-tab test on one Mac the direct link measured 1 ms. On the real TV with a real phone, the screenshot in log 04 shows the meter at "Direct · 7–10 ms", but I haven't run a proper measurement yet, so I'm not claiming a number.
Shipping a TizenBrew module
TizenBrew loads modules from GitHub through the jsDelivr CDN. Two things there cost real time:
- A version-less jsDelivr GitHub URL resolves to the latest git tag, and the CDN caches files for hours. So every release is tagged, and the script gets a new file name each time (
dist/inject-1.6.0.js), so a stale copy can never be served. - TizenBrew caches module code in its own service, so the TV only picks up a new release after a restart.
- Version 1.0 never opened at all. It asked TizenBrew to inject at document start, which waits for a debugger event that never fires when you launch from the menu. 1.0.1 injects per page, like TizenTube, and works.
| Version | What changed |
|---|---|
| 1.0.1 | First version that opens: inject per page |
| 1.2 | Pair through the cloud relay (the mixed-content wall) |
| 1.3 | GPU-layer cursor, one redraw per frame, phone batches moves every 20 ms |
| 1.4 | Per-site text size |
| 1.5 | Jump mode |
| 1.6 | WebRTC direct link and the live delay meter |
What still doesn't work
- Google sign-in refuses the TV's browser engine. The only workaround is to fake being another browser, and I decided not to.
- Some sites ignore clicks and keys that come from a script (they're marked "untrusted"), and Reddit's security policy blocks the phone connection. The remote cursor still works there.
- Heavy sites lag. That's the TV's CPU, not the link.
It's open source and installable from TizenBrew's module manager: github.com/prutxvi/tv-browser-plus.