BrightScript Engine API
August 4, 2026 · View on GitHub
The engine worker library (brs.worker.js), has a programmable interface (brs.api.js), built in packages/browser/lib/, with the goal to facilitate the integration of the engine into web based applications.
Check the documentation to learn how to start using it. The only pre-requisites are to expose, on the default document, a canvas object named display and a video object named player, and optionally, if you want to show the performance statistics, you also need to expose a div object named stats.
Methods
| Method | Description | Parameters / Details |
|---|---|---|
async initialize(customDeviceInfo?, options?) | Initializes the engine simulated device |
|
subscribe(observerId, observerCallback) | Subscribes to the engine events (see list below) |
|
unsubscribe(observerId) | Unsubscribes to the engine events |
|
execute(filePath, fileData, options?, deepLink?) | Loads and run an app package (.zip/.bpk), a source code file (.brs) or plain text BrightScript code |
|
terminate(reason) | Terminates the current app/source code execution |
|
redraw(fullScreen, width?, height?, dpr?) | Requests a display redraw (always keeps the aspect ratio based on display mode) |
|
setDisplayMode(mode) | Configures the display mode (if an app is running will reset the simulated device) |
|
| getDisplayMode() | Returns the current display mode. | |
setOverscanMode(mode) | Configures the overscan mode. |
|
| getOverscanMode() | Returns the current overscan mode. | |
setCaptionMode(mode) | Configures the closed caption mode. |
|
| getCaptionMode() | Returns the current closed caption mode. | |
setCaptionStyle(style) | Configures the closed caption style options. |
|
| getScreenshot() | Returns an ImageData with the latest rendered screenshot or null if not available. | |
setFrameNotify(enabled) | Enables or disables the framePainted and frameCleared events (see list below). Disabled by default, so it costs nothing when unused. Enable it if you mirror the display elsewhere, for example into a video stream, and need to know when it changed instead of polling for it. |
|
| getDisplayBuffer() | Returns the OffscreenCanvas the visible display is drawn from, or null if the display is not initialized. Unlike the display canvas it has no overscan guidelines and is at the resolution the app actually renders at, which makes it the canvas to copy when mirroring the screen. That resolution is the app's screen size (roScreen/roSGScreen), not necessarily the display mode's: CreateObject("roScreen", true, 640, 480) renders 640x480 in any mode. It is the live buffer, so treat it as read-only; the object stays valid for the session, but its dimensions change with the app's screen, so re-read them on each frame (a resolution event is raised before every change). | |
enableStats(state) | Enables or disables the performance stats overlay |
|
setAudioMute(mute) | Mutes or un-mutes the audio during app execution |
|
| getAudioMute() | Returns true if the audio is muted | |
setRendezvousLog(enable) | Enables or disables tracing of SceneGraph cross-thread rendezvous — the equivalent of Roku's logrendezvous. Each field read, field write and method call that crosses a thread reports its action, target and duration as a debug event to subscribers. Takes effect immediately, including on Task threads already running, and persists across execute() calls until changed. Verbose on task-heavy apps. |
|
| getRendezvousLog() | Returns true if rendezvous tracing is enabled | |
| getSerialNumber() | Returns the device serial number, this value changes when the deviceData.deviceModel is updated. | |
setControlMode(controls) | Enable/Disable the remote control simulation | controls (object) contains following properties:
|
| getControlMode() | Returns an object with the control mode flags | Same options sent to the setControlMode above. |
setCustomKeys(keysMap) | Sends a custom map of keyboard keys to add/remove from the remote control simulation |
|
setCustomPadButtons(buttonsMap) | Sends a custom map of game pad buttons to add/remove from the remote control simulation |
|
sendKeyDown(key, remote?, index?) | Sends a remote control key down event to the engine |
|
sendKeyUp(key, remote?, index?) | Sends a remote control key up event to the engine |
|
sendKeyPress(key, delay?, remote?, index?) | Sends a remote control key press event to the engine |
|
sendInput(params) | Sends custom events to the current application to be raised by roInput component |
|
mountExt(zipData) | Mounts a zip file as the external volume ext1: |
|
| umountExt() | Unmounts the external volume ext1: | |
updateMemoryInfo(used, total) | A method for the host application to inject memory usage information to the engine. |
|
debug(command) | Sends a debug command to the Engine |
|
| getDebugState() | Returns true if debug functionality is enabled, false if disabled | |
setDebugState(enabled) | Enables or disables the debug functionality |
|
| getVersion() | Returns the version of the API library | |
isEncryptedPackage(fileData) | Returns true if the data is an encrypted package container created by encryptPackage() (a plain .zip or a legacy .bpk returns false) |
|
async encryptPackage(zipData, password) | Wraps a package in an AES-256-CTR container so even the plaintext assets are unreadable at rest. Used when creating a .bpk |
|
async decryptPackage(fileData, password) | Unwraps a container produced by encryptPackage(). Plain zips and legacy .bpk files are returned untouched, so it is safe to call unconditionally |
|
requestBitmaps(timeoutMs) | Requests the current texture-memory state (the list of bitmaps and registered fonts loaded into memory, plus memory totals), equivalent to a Roku device's query/r2d2-bitmaps ECP endpoint. Returns a Promise that resolves with the data (or undefined if no app is running or the request times out). The same data is also dispatched to subscribers via the bitmaps event. Requires developer mode: the app must run with debugOnCrash: true (see execute), otherwise the bitmap list is empty. |
|
setRendezvousTracking(enable) | Enables or disables ECP-style SceneGraph rendezvous tracking — the equivalent of Roku's sgrendezvous/track and sgrendezvous/untrack ECP commands. Independent of setRendezvousLog: instead of printing console lines, it collects structured RendezvousEvent records ({id, startTm, endTm, line, file}) for requestRendezvousEvents() and the rendezvous event, so a host application can implement its own ECP sgrendezvous route by calling into this API. Enabling clears any previously queued events. Requires developer mode, matching Roku's requirement for this ECP command. |
|
| getRendezvousTracking() | Returns true if ECP-style rendezvous tracking is enabled | |
| requestRendezvousEvents() | Returns the rendezvous events queued since tracking was enabled or since the previous call to this function, then drains the queue — mirroring the "since tracking was enabled, or since the previous call" semantics of Roku's query/sgrendezvous. | Returns {events: RendezvousEvent[], dropCount: number}; dropCount counts events dropped because the queue exceeded its 1,000-event cap. |
Common API exports
The browser API now re-exports a small set of shared types and constants so host applications can configure the simulated device and extension pipeline without digging into internal modules.
| Export | Description | Usage Examples |
|---|---|---|
DeviceInfo | Type describing the simulated Roku device, including new extensions?: Map<SupportedExtension, string> for host-provided extension wiring. | Use to type-check custom device overrides passed to initialize(customDeviceInfo) and set each value to the worker-accessible path (e.g., "./brs-sg.js"). |
DefaultDeviceInfo | Baseline DeviceInfo object used by the engine. | Clone or spread this object before applying overrides so you only touch the fields you care about. |
Platform | Runtime detection helper indicating whether the interpreter runs in the browser, worker, or Node. | Gate host-specific logic (e.g., only attach audio/video handlers when Platform.inBrowser is true). |
AppExitReason | Enum describing the reason the previous app exited. | Compare against deviceData.appList entries or populate deep-link metadata with the appropriate reason string. |
SupportedExtension | Enum of known first-party extensions (brs-scenegraph, future SDK1/BrightSign IDs). | Reference when registering extensions in DeviceInfo.extensions so you avoid typos. |
Events
| Event | Description | Data Type |
|---|---|---|
| loaded | Triggered when the source code data has finished loading | object: {id: string, file: string, title: string, subtitle: string, version: string, running: boolean} |
| icon | Triggered when the zip file is loaded and manifest links to a valid icon for the app | base64: A base64 string of the app icon, extracted from the zip file. |
| registry | Triggered when the app updates the registry | Map: the registry with all recent recent updates. |
| started | Triggered when the engine started running the source code | object: {id: string, file: string, title: string, subtitle: string, version: string, running: boolean} |
| closed | Triggered when the engine terminated the execution of the source code | string: the exit reason based on Roku documentation |
| reset | Triggered when the RebootSystem() function is executed from the engine | null: Nothing is returned as data |
| control | Triggered when a control key is sent to the engine | object: {key: string, mod: number}. The property key contains an ECP key code and mod contains 0 for key down or 100 for key up |
| captionMode | Triggered when the closed caption mode is changed | string: The new caption mode, options are "Off", "On", "Instant replay", "When mute" |
| redraw | Triggered when the display canvas is redrawn/resized | boolean: If true the display canvas is in full screen mode |
| resolution | Triggered when the emulated screen resolution changes (controlled via BrightScript) | object: {width: integer, height: integer} |
| framePainted | Triggered when the display canvas is repainted from the display buffer, but only while setFrameNotify(true) is active. The engine repaints on demand rather than on a timer, so this is the only way to know when the screen actually changed. Raised after the repaint, so getDisplayBuffer() holds the frame just drawn. Named apart from the brs-node library's frame event, which reports the raw worker frame as an ImageData | number: a monotonic frame counter, restarted at each setFrameNotify(true) call |
| frameCleared | Triggered when the display canvas is blanked, for instance when an app exits or the app disables the display via roAppManager.setDisplayDisabled(), but only while setFrameNotify(true) is active. Separate from framePainted because the display buffer is deliberately left untouched, so it still holds the last drawn image: an embedder mirroring the screen has to blank its own copy rather than copy the buffer. Consecutive blanks are collapsed into one event | null: Nothing is returned as data |
| display | Triggered when the display mode is changed via setDisplayMode() (a running app is terminated first) | string: the new display mode, options are "480p", "720p" or "1080p" |
| launch | Triggered when the methods roAppManager.launchApp() or roNDK.start() (with SDKLauncher app) are called from BrightScript | object: {app: string, params: Map}. |
| browser | Triggered when the library sub RokuBrowser is called from BrightScript | object: {url: string, width: integer, height: integer}. The parameters width and height defines the dimensions of the browser window |
| debug | Triggered when debug messages arrive from the worker library (BrightScript Interpreter) | object: {level: string, content: string}, levels are: print, beacon, debug, warning, error, stop, pause, continue |
| version | Triggered when the worker library (BrightScript Interpreter) reports its version | string: the worker library version |
| bitmaps | Triggered when texture-memory data arrives from the worker library in response to requestBitmaps() | object: {timestamp: number, channelId: string, systemMemory: {used: number}, textureMemory: {used: number, available: number, max: number}, bitmaps: Array<{address: string, width: number, height: number, bpp: number, size: number, name: string}>} |
| rendezvous | Triggered for each SceneGraph cross-thread rendezvous while setRendezvousTracking(true) is active | object: {id: number, startTm: number, endTm: number, line: number, file: string} |
| error | Triggered when the any execution exception happens on the API library | string: The message describing the error |