BrighterScript Game Engine
An object-oriented game engine and 2D/3D drawing library for Roku, written in BrighterScript.
Build a full game with entities, rooms, collisions, input, and UI - or just pull in the renderer to draw sprites, shapes, billboards, and wireframe/solid 3D models on top of your own Roku app. Same engine, use as much or as little of it as you need.

Asteroids example - 2D movement, collisions, and scoring

3D example - loading and rendering .stl 3D models with the pseudo-3D renderer

Snake example - grid-based movement and a growing collision shape
Why BrighterScript Game Engine?
- Object-oriented, like the engines you already know.
GameEntity,Room, and lifecycle hooks (onCreate,onUpdate,onCollision,onDrawBegin/onDrawEnd, ...) give you the same shape as Phaser, HaxeFlixel, GameMaker, or Unity - minus the visual editor. - A real 2D/3D renderer, not just sprite blitting. Draw images, sprites, animations, shapes, text, and billboards, or render actual 3D models (loaded from
.stl) with wireframe, solid, and shaded draw modes - all built on Roku'sroCompositor/Draw2D, so it runs on real hardware. - Built-in collisions, input, UI, and debug tooling. Circle/rectangle colliders, a retained-mode UI widget tree, and debug overlays (FPS, colliders, memory, GC stats) come standard, so you're not rebuilding the basics for every project.
- Use only what you need. The
Renderer/Canvaslayer works standalone if you just want a capable drawing library for an existing Roku app, without adopting the full game loop. - Develop without a physical Roku. This engine supports running under the BrightScript Simulator, Marcelo Lv Cabral's desktop BrightScript simulator, so you can iterate on your game without deploying to hardware every time.
A quick taste
sub main()
game = new BGE.Game(1280, 720)
game.fitCanvasToScreen()
game.loadBitmap("player", "pkg:/sprites/player.png")
room = new MainRoom(game)
game.defineRoom(room)
game.changeRoom(room.name)
game.play()
end subclass MainRoom extends BGE.Room
sub new(game as BGE.Game)
super(game)
m.name = "MainRoom"
end sub
override sub onCreate(args as roAssociativeArray)
m.game.addEntity(new Player(m.game))
end sub
end classclass Player extends BGE.GameEntity
sub new(game as BGE.Game)
super(game)
m.name = "Player"
end sub
override sub onCreate(args as roAssociativeArray)
m.position = m.game.canvas.renderer.getCanvasCenter()
bitmap = m.game.getBitmap("player")
region = CreateObject("roRegion", bitmap, 0, 0, bitmap.GetWidth(), bitmap.GetHeight())
m.addImage("sprite", region)
m.addCircleCollider("body", bitmap.GetWidth() / 2)
end sub
override sub onInput(input as BGE.GameInput)
m.velocity.x = input.x * 10
m.velocity.y = input.y * 10
end sub
override sub onCollision(myCollider as BGE.Collider, otherCollider as BGE.Collider, otherEntity as BGE.GameEntity)
m.game.postGameEvent("player_hit", {by: otherEntity})
end sub
end classThis exact code lives in examples/quickstart as a runnable app. See the Documentation for the full API, and the examples below for complete, runnable projects.
Examples
The examples/ directory has full Roku channels you can build and run:
| Example | What it shows |
|---|---|
quickstart | The minimal MainRoom/Player example from above, as a runnable app |
asteroids | A complete 2D game - player movement, bullets, collisions, particle-style explosions, sound |
pong | Classic 2D Pong, playable in both 2D and 3D camera modes |
snake | Grid-based movement and growing collision shapes, in 2D and 3D |
3d | Loading and rendering .stl 3D models with the pseudo-3D renderer |
pixels | A tour of drawables - polygons, rectangles, sprites, and more, one room per shape |
canvas | Using the engine's canvas/renderer as a standalone drawing surface |
hybrid | Mixing this engine's Draw2D-based rendering with a SceneGraph app |
rendererTest | A manual test harness used while developing the renderer itself |
Scaffold a new example (manifest, icons/splash, package.json, a minimal MainRoom) with:
npm run create-example -- <name> ["Display Title"]Cloning and Running Examples
The BrighterScript Game Engine public repository is on Github
Clone the project:
git clone https://github.com/markwpearce/brighterscript-game-engine.gitThis project includes various example Roku apps in the examples directory. To run them, you will need a Roku and have it set up properly for doing development. See: https://developer.roku.com/en-ca/docs/developer-program/getting-started/developer-setup.md.
To run the examples:
Install dependencies:
cd brighterscript-game-engine
npm installYou will need to set up each project in the examples directories. You can do this by using this script:
npm run prepare-examplesBuild from the command line:
You can manually build the examples from the command line and manually add the zip files to your Roku:
npm run build-examplesThe above command will generate example .zip files like ./examples/asteroids/out/bge-asteroids.zip
Open the Workspace in VS Code:
We recommend you install the great Brightscript Language VSCode Extension.
Create/edit a .env file to specify the details for you target Roku device:
ROKU_USERNAME=<roku development username - default is rokudev>
ROKU_PASSWORD=<roku development password>
ROKU_HOST=<local IP address of the target roku>Then simply run one of the Debug configurations from the Debug tab.
Installation
Add it as a dependency and install with ropm:
npm install brighterscript-game-engine
ropm installBy default, ropm renames every package's namespace to avoid collisions - so without any extra config, you'd need to reference the engine through its installed name, e.g. new brighterscriptgameengine.BGE.Game(...).
To use the engine directly as BGE.* (as shown throughout this README and the examples), add ropm.noprefix for it to your own project's package.json - this is a per-consumer opt-out, safe to use because BGE is this engine's own deliberate top-level namespace, not an auto-generated one:
{
"ropm": {
"noprefix": ["brighterscript-game-engine"]
}
}Also add the standard roku_modules diagnostic filter to your bsconfig.json - this is a normal, expected pattern for any project consuming ropm dependencies (this engine's own bsconfig.base.json does the same for its rodash dependency), and avoids noise from a couple of known upstream ropm/brighterscript typedef-validation issues (rokucommunity/ropm#148, rokucommunity/brighterscript#1757):
{
"diagnosticFilters": [
{ "files": "**/roku_modules/**" }
]
}Known limitation: subclassing BGE.Room/BGE.GameEntity
Subclassing one of the engine's own classes and passing an instance back into an engine method (e.g. game.defineRoom(new MainRoom(game)), or calling super(game) in your subclass's constructor) currently trips a real upstream brighterscript bug (rokucommunity/brighterscript#1758): the generated type declarations reference the class's internal compiled name instead of its real type, so bsc --validate reports an argument-type-mismatch for this - completely ordinary and expected - pattern. The roku_modules filter above doesn't cover this, since the error is reported against your own file, not a roku_modules one.
This is a static type-checker false positive only - type annotations aren't enforced at runtime, so your game still runs correctly regardless. If your own CI gates on bsc --validate reporting zero errors, you'll need to account for this until it's fixed upstream.
Documentation
Documentation can be found here
Acknowledgements
This project was originally forked from Roku-gameEngine by Austin Sojka, and converted into BrighterScript. This work owes a lot to this original project!
Thanks also to:
- RokuCommunity for BrighterScript, bslint, roku-deploy, and the rest of the tooling that makes this project possible.
- Marcelo Lv Cabral for his work on the Roku/BrightScript community and tooling, including the BrightScript Simulator this engine supports developing against.