source/ and SceneGraph XML+BRS components under components/ — that communicate through the RSG scene tree and shared global state.
Roku SceneGraph fundamentals
Roku SceneGraph is a declarative UI framework built on a node tree. Every visual element and background task is a node. Key system concepts used by this app:- Scene tree —
MainSceneextends the built-inScenenode and is the root of the entire tree. All screens and tasks are children ofMainScene. - roSGScreen — the Roku system object that renders the SceneGraph. Created in
main.brs, it owns a singleMainScene. - roMessagePort — the event loop in
main.brs. Thewhile trueloop waits on this port to receiveroSGScreenEvent,roSGNodeEvent,roInputEvent, androDeviceInfoEventmessages. - Tasks — SceneGraph
Tasknodes run BrightScript on a background thread. They expose observable fields so the scene thread can react to results without blocking the UI. - observeField / onChange — the wiring mechanism. When a field value changes, RSG calls the registered handler on the same thread as the observer.
- m.global — a globally shared
roSGNodeaccessible from every component and task in the app.AppState.brsinitialises all fields on it at startup.
Source layer (source/)
Code under source/ runs on the render thread inside MainScene. It is loaded via <script> tags in MainScene.xml.
| File | Role |
|---|---|
main.brs | Entry point. Creates roSGScreen, instantiates MainScene, detects deep links, runs the event loop, and monitors device memory. |
AppConstants.brs | Single source of truth for all configuration: server URLs, API paths, timeouts, registry keys, UI constants, colour palette, and auth reason codes. |
AppState.brs | GTV_InitGlobalState() — adds every m.global field with its default value. Also contains layout helpers (GTV_GetLayoutContext, GTV_GetSafeArea) and auth signal classification (GTV_AuthClassifyFailure). |
utils/Logger.brs | GTV_Log() (dev only), GTV_Warn(), GTV_Error() — tagged log functions. |
utils/HttpClient.brs | Synchronous HTTP wrapper for use inside Task nodes. |
utils/RegistryManager.brs | Read/write helpers for the Roku persistent registry (roRegistrySection). Stores credentials, last server URL, last channel index, safe-margin percentage, and server profiles. |
utils/ServerManager.brs | Server profile CRUD, URL normalisation, and health-check probing. |
utils/M3UParser.brs | Parses M3U8 playlist files into channel and category arrays. |
utils/HealthCheck.brs | HTTP health-check against /health with configurable timeout. |
utils/NetworkDetector.brs | GTV_IsOnline() — checks the active network interface without making an HTTP request. |
Components layer (components/)
Screens
MainScene, SplashScreen, OnboardingScreen, LoginScreen, MainScreen, PlayerScreen, SettingsScreen — the full user-facing UI hierarchy from launch through playback.Background tasks
HandshakeTask, AuthTask, PlaylistTask, ConnectivityTask, AdsPollingTask, MetricsTask, ServerProbeTask — all network I/O runs off the render thread.Ad system
AdManager coordinates three format renderers: AdFormatA, AdFormatB, and AdFormatC. Format C reduces the video viewport height. Ad data arrives from AdsPollingTask every 10 seconds.Overlays
channelBanner shows channel name, number, logo, and live status. numberOverlay handles direct numeric channel entry. Both overlay the live video during playback.Component responsibilities
| Component | Type | Responsibility |
|---|---|---|
MainScene | Scene (root) | Global state init, screen orchestration, task lifecycle, deep link routing, session auth checks, exit flow |
SplashScreen | Screen | Displays the launch splash for SPLASH_MS (1500 ms), then fires splashDone |
OnboardingScreen | Screen | First-run welcome screen; routes to LoginScreen via goToLogin |
LoginScreen | Screen | On-device credential form; requests Roku email via ChannelStore.getUserData; runs AuthTask |
MainScreen | Screen | Category-tabbed channel grid; signals AppLaunchComplete beacon on first channel load; doubles as the channel-selection overlay during playback |
PlayerScreen | Screen | HLS playback via Video node; hosts AdManager, channel banner, number overlay, error and offline dialogs; spawns ConnectivityTask, AdsPollingTask, and MetricsTask |
SettingsScreen | Screen | Safe-area adjustment, channel refresh, logout, server management (admin-unlocked) |
HandshakeTask | Task | Discovers the active server via health-check across the server list; writes activeServer to m.global |
AuthTask | Task | Authenticates username/password against /auth/{user}/{pass}; returns success or failure with a classified reason code |
PlaylistTask | Task | Downloads and parses the M3U8 playlist from /auth/{user}/{pass}/playlist/m3u8/hls; returns channels and categories arrays |
ConnectivityTask | Task | Polls internet reachability every NET_RETRY_MS (30 s); updates m.global.hasInternet |
AdsPollingTask | Task | Performs ads handshake, then polls /app/ads/active every ADS_POLL_MS (10 s); signals inactivity and session invalidation |
MetricsTask | Task | Batches and POSTs impression events to /api/v1/app/metrics/track |
ServerProbeTask | Task | One-shot health-check for a given server URL; used by the settings server-test action |
AdManager | Component | Receives ad snapshots; selects and renders the correct format node; manages video viewport reduction for Format C |
AdFormatA/B/C | Component | Individual ad renderers; Format C emits videoHeightReduction and videoOffsetY to compress the video area |
Utility layer
All utilities are pure BrightScript functions loaded as<script> includes into MainScene.xml. They carry no node state and can be called from any script that shares the same component scope.
Design resolution and safe area
GTV_GetDesignSize() detects the display mode (roDeviceInfo.GetDisplayMode()) and returns 1920×1080 or 1280×720. GTV_GetSafeArea() applies the uiSafeMarginPct registry value (0–10 %) to compute inset bounds. All screens call ApplyResponsiveLayout() on init and whenever currentDesignResolution changes, keeping the layout consistent across FHD and HD Roku models.