A lightweight BrightScript simulator running in a Node.js + Docker environment β designed to let you execute and iterate on Roku .brs projects directly from your browser.
This is not a full Roku device emulator, but a generic simulator built on top of brs, the open-source BrightScript interpreter.
Currently, it supports simple script execution and live reload, with plans to expand toward UI scene simulation.
The simulator runs a Node.js web server that:
- Watches your BrighterScript project (
source/**/*.bs) for changes (hot-reload). - Compiles BrighterScript β BrightScript using
bsc(from thebrighterscriptpackage). - Generates compiled
.brsfiles into the project'sdist/directory (staging dir). - Serves a web UI with:
- Build log showing compile status, errors, and warnings.
- Compiled file viewer for inspecting generated
.brssource code. - Execute button to run the compiled code via the
brsCLI and display runtime output.
- Uses Server-Sent Events (SSE) to stream logs live to connected browser clients.
This is intended as a local dev environment to quickly test BrightScript logic (console output), not full Roku SceneGraph rendering.
docker-compose.yml example:
services:
brs-sim:
build: .
container_name: brs-sim
ports:
- "8080:8080"
environment:
- PROJECT_PATH=/app/projects
- PROJECT=hello-world # or hello-screen
- FILE=source/main.brs
- PORT=8080
volumes:
- ./projects:/app/projects
working_dir: /app/projects/hello-worlddocker compose up --buildThen open in your browser:
http://localhost:8080
You will see:
- Build Log: Live updates as you edit
.bsfiles. - Compiled Files: Click a file tab to view the generated
.brscode. - Execute Button: Run the compiled code and see runtime
stdoutoutput.
.
βββ Dockerfile # Node 18 + brighterscript + brs
βββ docker-compose.yml # Service config with hot-reload mounts
βββ server.js # Express server + watcher + compile/execute orchestration
βββ package.json # Dependencies: express, brighterscript, brs, chokidar
βββ public/ # Static web UI (build log, file viewer, Execute button)
βββ projects/
β βββ hello-world/ # Simple console output example
β β βββ bsconfig.json # BrighterScript compiler config
β β βββ manifest # Roku manifest (metadata)
β β βββ source/ # BrighterScript source (.bs files)
β β β βββ main.bs
β β β βββ greet.bs
β β βββ dist/ # Generated by bsc (staging dir)
β βββ hello-screen/ # UI scene example with ASCII rendering
β βββ bsconfig.json # BrighterScript compiler config
β βββ manifest # Roku manifest (metadata)
β βββ source/ # BrighterScript source (.bs files)
β β βββ main.bs
β βββ dist/ # Generated by bsc (staging dir)
projects/hello-world/source/main.bs
import "./greet.bs"
sub main() as void
print "Hello from main.bs"
Greet.Greet_Hello("developer")
end sub
main()projects/hello-world/source/greet.bs
namespace Greet
function Greet_Hello(name as string)
print "Hello " + name
end function
end namespaceWhen you click Execute, the server runs the compiled .brs files (via npx brs) and displays output:
Hello from main.bs
Hello developer
projects/hello-screen/source/main.bs demonstrates a simple scene with UI elements:
sub main() as void
print "=== Hello Screen Demo ==="
scene = CreateHelloScene()
print "Message: " + scene.message
RenderScene(scene)
end sub
function CreateHelloScene() as object
scene = {
message: "Welcome to BrightScript UI Demo!"
colors: { background: "#1a1a1a", text: "#ffffff", accent: "#00a8ff" }
elements: [
{ type: "Label", text: "Hello Screen" }
{ type: "Button", text: "Start", width: 200, height: 50 }
]
}
return scene
end function
function RenderScene(scene as object) as void
print "β" + string(50, "β") + "β"
print "β " + CenterText(scene.message, 48) + " β"
print "β" + string(50, "β") + "β€"
' Render UI elements with ASCII art...'
print "β" + string(50, "β") + "β"
end functionOutput when executed:
=== Hello Screen Demo ===
Message: Welcome to BrightScript UI Demo!
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Welcome to BrightScript UI Demo! β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Hello Screen
β ββββββββββββββββββββββββββ
β β Start β
β ββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
To test the hello-screen project, update your docker-compose.yml:
- Change
PROJECT=hello-worldtoPROJECT=hello-screen - Change
working_dirto/app/projects/hello-screen - Then run
docker compose up --build
- Watch:
chokidarmonitorsprojects/<PROJECT>/source/**/*.bsfor changes. - Compile: On file change, runs
npx bsc --project bsconfig.json(withcwdset to the project folder) to transpile BrighterScript β BrightScript intodist/source/. - List: Scans
dist/for compiled.brsfiles and broadcasts "Build completed" to all connected UI clients via SSE. - Serve UI:
/serves a web page with a build log (live streamed), a compiled-files viewer, and an Execute button. - Execute:
GET /executerunsnpx brs <compiled-files...>(excludingbslib.brs) and returns runtimestdout.
Important notes:
- The compiler runs from the project directory so
stagingDir: "dist"resolves correctly inside the project (avoiding nesteddist/dist/...issues). - Compiled files are filtered to exclude
bslib.brsfrom execution (it's a runtime support library). - All events (build status, errors, runtime output) are streamed to the browser via SSE so the UI stays synchronized.
| Variable | Default / Example | Description |
|---|---|---|
PROJECT_PATH |
/app/projects |
Root directory of projects |
PROJECT |
hello-world |
Target project folder name |
FILE |
source/main.brs |
Entry BrightScript file path |
PORT |
8080 |
Port for the simulator UI |
- No SceneGraph or UI rendering β console-only output.
- Limited BrightScript APIs β depends on what
brssupports. - No package or Roku channel bundling β runs individual
.brsfiles only. - Environment variables are not yet exposed inside BrightScript global AA.
Planned improvements:
- Basic SceneGraph mock rendering (HTML canvas-based).
- API stubs for Roku built-ins.
- UI to edit and run scripts inline from the browser.
If you prefer to run directly without Docker:
npm install
npm startThen set your .env:
PROJECT_PATH=./projects
PROJECT=hello-world
FILE=source/main.brs
PORT=8080
| Method | Path | Description |
|---|---|---|
GET |
/ |
Web UI |
GET |
/compiled-files |
Returns JSON array of compiled .brs files in dist/ |
GET |
/execute |
Runs compiled code via npx brs and returns { output: "..." } |
GET |
/status |
Returns simulator status |
GET |
/restart |
Restarts BrightScript process |
GET |
/events |
Server-sent event stream (live logs) |
MIT β free to use and extend.