Overview
tv.visionplus.id started with a partner request. Hotels treat the in-room television as a core guest facility, and Park Hyatt Jakarta runs WebOS Smart TVs in their rooms. Guests wanted VISION+ there. VISION+ didn't have a TV client.
I built one — a Smart TV application for WebOS and Tizen, covering the full path from browsing to watching.
The business case ran further than one hotel. A TV app made VISION+ demonstrably multi-platform, reaching a screen its competitors largely weren't on.
TV Is Not a Small Web Browser
Two constraints define this platform, and both bite early.
The hardware is weak. A Smart TV SoC is years behind the phone in your pocket. Framework overhead that's invisible on mobile becomes visible input lag on a television — and lag on a remote control feels broken in a way lag on a touchscreen does not.
There is no cursor. Navigation is a D-pad: up, down, left, right, OK, back. Every screen is a focus graph, and if focus order is wrong the app is unusable regardless of how it looks.
Why SolidJS
I chose SolidJS for the first constraint. Fine-grained reactivity means state changes update exactly the DOM nodes affected — no virtual DOM diff, no reconciliation pass. Combined with a small runtime, that's the difference between a remote press that feels instant and one that feels sluggish.
On a TV, that gap is the whole product experience.
Virtualized Content Rows
The home surface is built from horizontal sliders:
- Banner slider — featured content
- Category sliders — one row per genre or collection
- "Like This" slider — recommendations
A content row can be long, and users scroll it fast by holding a direction key. Rendering every card means dropped frames the moment a row grows.
TanStack Virtual renders only what's on screen and recycles nodes as focus moves. Rows stay smooth regardless of length, and memory stays flat — which matters on hardware where a leak means a crash, not a slowdown.
Content Detail
The detail page carries product metadata, the episode list for series, and a similar-content slider to keep the browse loop going rather than dead-ending.
Every element is D-pad reachable in an order that matches how someone actually reads the screen. Focus management was designed per screen, not inherited from DOM order.
Buying From the Couch
I built a buy-package page so a guest can subscribe directly on the TV.
This is a genuinely awkward flow — a purchase, on a remote control, with an on-screen keyboard. The design goal was minimizing keystrokes: the fewer characters a user has to enter with a D-pad, the more purchases complete.
Streaming
I integrated Shaka Player into the streaming page for adaptive bitrate and DRM.
Live events are the hardest case. Bandwidth shifts, the stream can't buffer ahead the way VOD can, and a viewer who gets a stall during a live match doesn't come back later — the moment is gone. Shaka's ABR handling kept quality adapting rather than stalling.
Viewer retention during live streaming rose 25%.
State, Data, Tooling
- Nano Stores — shared state, chosen for the same reason as Solid: minimal runtime cost
- Axios — API layer with interceptors for auth and error handling
- SCSS — styling, with TV-safe areas and overscan margins baked into the layout system
- Tizen Studio — Samsung packaging and on-device testing
Emulators lie about TV performance. Real-device testing was non-negotiable.
Results
- 22% increase in new users from a platform VISION+ previously didn't reach
- 25% higher viewer retention during live streaming events
- Deployed on Park Hyatt Jakarta in-room Smart TVs
- VISION+ established across mobile, web, and television
Stack
SolidJS · TanStack Virtual · Nano Stores · SCSS · Axios · Shaka Player · Tizen Studio
Matching
A tiered strategy runs exact matches first, then windowed amount/date matching, then fuzzy reference scoring.
Auditability
Every match and override is appended to an immutable decision log.
