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

MethodDescriptionParameters / Details
async initialize(customDeviceInfo?, options?)Initializes the engine simulated device
  • customDeviceInfo? (object): customized device information, see /src/core/common.ts for valid properties.
  • options? (object): init options, valid properties are:
    - showStats(boolean): if true the performance statistics overlay will be shown over the display when the app is running, default is false.
    - disableDebug(boolean): if true prevents any debug command/data to be sent or received by the engine, for production to avoid code injection, default is false.
    - debugToConsole(boolean): if false prevents messages to be sent to the console, you still can debug messages via debug event, default is true.
    - disableKeys(boolean): if the engine is running on a device with no keyboard, or you don't need keyboard control, set this option to true to disable keyboard control, default is false
    - customKeys(Map): a custom map of keyboard keys to add/remove from the remote control simulation, see /src/api/control.ts for the default mappings.
    - disableGamePads(boolean): Set this option to true if you want to disable the game pad control support, default is false
    - customPadButtons(Map): a custom map of GamePad buttons (0-31) to add/remove from the remote control simulation, see /src/api/control.ts for the default mappings.
subscribe(observerId, observerCallback)Subscribes to the engine events (see list below)
  • observerId (string): identifier of the subscriber process.
  • observerCallback (function): callback function to receive the events from the engine.
unsubscribe(observerId)Unsubscribes to the engine events
  • observerId (string): identifier of the subscriber process.
execute(filePath, fileData, options?, deepLink?)Loads and run an app package (.zip/.bpk), a source code file (.brs) or plain text BrightScript code
  • filePath (string): path of the loaded file, make sure extension is .zip or .bpk if loading a full app.
  • fileData (ArrayBuffer/Blob/string): contents of the file or just a string with BrightScript code.
  • options? (object): execution options, valid properties are:
    - clearDisplayOnExit (boolean): if false the display will keep the last image when app ends, default is true.
    - muteSound (boolean): if true the engine will mute all audio but events are still raised, default is false.
    - entryPoint (boolean): Change the property in DeviceInfo with same name, if true will raise a warning when the app has no entry point, functions Main() or RunUserInterface(), default is true.
    - debugOnCrash (boolean): Change the property in DeviceInfo with same name, if true stops on the Micro Debugger when a crash happens, default is false.
    - logRendezvous (boolean): if true traces every SceneGraph cross-thread rendezvous as debug events, same as setRendezvousLog below, default is false.
    - password (string): the password to decrypt a .bpk, or encrypt a .zip package, default is "".
  • deepLink? (Map): Parameters to be passed to the application as deep link.
terminate(reason)Terminates the current app/source code execution
  • reason (string): the reason for the termination to be shown on debug.
redraw(fullScreen, width?, height?, dpr?)Requests a display redraw (always keeps the aspect ratio based on display mode)
  • fullScreen (boolean): Flag to inform if the full screen mode is activated.
  • width? (number): width of the canvas, if not passed uses globalThis.innerWidth.
  • height? (number): height of the canvas, if not passed uses globalThis.innerHeight.
  • dpr? (number): device pixel ratio, if not passed uses globalThis.devicePixelRatio.
setDisplayMode(mode)Configures the display mode (if an app is running will reset the simulated device)
  • mode (string): supported modes are "480p" (SD), "720p" (HD) or "1080p"(FHD).
getDisplayMode()Returns the current display mode.
setOverscanMode(mode)Configures the overscan mode.
  • mode (string): supported modes are "disabled", "guidelines" or "overscan".
getOverscanMode()Returns the current overscan mode.
setCaptionMode(mode)Configures the closed caption mode.
  • mode (string): supported modes are "Off", "On", "Instant replay" or "When mute".
getCaptionMode()Returns the current closed caption mode.
setCaptionStyle(style)Configures the closed caption style options.
  • style (object[]): The caption styles array with each option as {id: string, style: string}, see options in Roku Documentation.
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.
  • enabled (boolean): if true every display repaint is reported.
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
  • state (boolean): if true performance statistics will be shown over the display, on the top left.
setAudioMute(mute)Mutes or un-mutes the audio during app execution
  • mute (boolean): if true the executing app audio and video will be muted.
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.
  • enable (boolean): if true cross-thread rendezvous will be traced.
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 simulationcontrols (object) contains following properties:
  • keyboard (boolean): if true enables the keyboard control.
  • gamePads (boolean): if true enables game pad control.
getControlMode()Returns an object with the control mode flagsSame 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
  • key (string): one of valid key codes (see Roku doc).
  • remote (number): one of valid remote types (see /src/core/common.ts) default is ECP.
  • index (number): The index of the remote control, default is 0.
sendKeyUp(key, remote?, index?)Sends a remote control key up event to the engine
  • key (string): one of valid key codes (see Roku doc).
  • remote (number): one of valid remote types (see /src/core/common.ts) default is ECP.
  • index (number): The index of the remote control, default is 0.
sendKeyPress(key, delay?, remote?, index?)Sends a remote control key press event to the engine
  • key (string): one of valid key codes (see Roku doc).
  • delay (number): the delay (in milliseconds) between sending Key Up and Key Down (default is 300ms).
  • remote (number): one of valid remote types (see /src/core/common.ts) default is ECP.
  • index (number): The index of the remote control, default is 0.
sendInput(params)Sends custom events to the current application to be raised by roInput component
  • params (object): An object with the parameters in the format {'string': 'string', ...}
mountExt(zipData)Mounts a zip file as the external volume ext1:
  • zipData (ArrayBuffer): The contents of a zip file to be mounted by the engine File System
umountExt()Unmounts the external volume ext1:
updateMemoryInfo(used, total)A method for the host application to inject memory usage information to the engine.
  • used (number): Memory used by the app (in KB)
  • total (number): Total memory available for the app (in KB)
debug(command)Sends a debug command to the Engine
  • command (string): the Micro Debugger can be enabled sending break command, and after that, any valid BrightScript expression or debug commands can be sent. You can also send pause to interrupt the interpreter, for instance, when the app loses focus. The command cont restarts the app. You can use this method on the browser console to debug your app.
getDebugState()Returns true if debug functionality is enabled, false if disabled
setDebugState(enabled)Enables or disables the debug functionality
  • enabled (boolean): if true enables debug commands and data to be sent/received by the engine, if false disables debug functionality for production to avoid code injection.
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)
  • fileData (Uint8Array): the raw package contents.
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
  • zipData (Uint8Array): the package contents to encrypt.
  • password (string): the raw AES-256 key, exactly 32 characters.
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
  • fileData (Uint8Array): the raw package contents.
  • password (string): the same 32-character key used to encrypt.
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.
  • timeoutMs (number, optional): how long to wait for a response before resolving with undefined (default 2000).
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.
  • enable (boolean): if true rendezvous events will be tracked.
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.

ExportDescriptionUsage Examples
DeviceInfoType 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").
DefaultDeviceInfoBaseline DeviceInfo object used by the engine.Clone or spread this object before applying overrides so you only touch the fields you care about.
PlatformRuntime 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).
AppExitReasonEnum describing the reason the previous app exited.Compare against deviceData.appList entries or populate deep-link metadata with the appropriate reason string.
SupportedExtensionEnum of known first-party extensions (brs-scenegraph, future SDK1/BrightSign IDs).Reference when registering extensions in DeviceInfo.extensions so you avoid typos.

Events

EventDescriptionData Type
loadedTriggered when the source code data has finished loadingobject: {id: string, file: string, title: string, subtitle: string, version: string, running: boolean}
iconTriggered when the zip file is loaded and manifest links to a valid icon for the appbase64: A base64 string of the app icon, extracted from the zip file.
registryTriggered when the app updates the registryMap: the registry with all recent recent updates.
startedTriggered when the engine started running the source codeobject: {id: string, file: string, title: string, subtitle: string, version: string, running: boolean}
closedTriggered when the engine terminated the execution of the source codestring: the exit reason based on Roku documentation
resetTriggered when the RebootSystem() function is executed from the enginenull: Nothing is returned as data
controlTriggered when a control key is sent to the engineobject: {key: string, mod: number}. The property key contains an ECP key code and mod contains 0 for key down or 100 for key up
captionModeTriggered when the closed caption mode is changedstring: The new caption mode, options are "Off", "On", "Instant replay", "When mute"
redrawTriggered when the display canvas is redrawn/resizedboolean: If true the display canvas is in full screen mode
resolutionTriggered when the emulated screen resolution changes (controlled via BrightScript)object: {width: integer, height: integer}
framePaintedTriggered 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 ImageDatanumber: a monotonic frame counter, restarted at each setFrameNotify(true) call
frameClearedTriggered 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 eventnull: Nothing is returned as data
displayTriggered 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"
launchTriggered when the methods roAppManager.launchApp() or roNDK.start() (with SDKLauncher app) are called from BrightScriptobject: {app: string, params: Map}.
browserTriggered when the library sub RokuBrowser is called from BrightScriptobject: {url: string, width: integer, height: integer}. The parameters width and height defines the dimensions of the browser window
debugTriggered 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
versionTriggered when the worker library (BrightScript Interpreter) reports its versionstring: the worker library version
bitmapsTriggered 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}>}
rendezvousTriggered for each SceneGraph cross-thread rendezvous while setRendezvousTracking(true) is activeobject: {id: number, startTm: number, endTm: number, line: number, file: string}
errorTriggered when the any execution exception happens on the API librarystring: The message describing the error