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.