brs-reference
Roku's official, open-sourced BrightScript + SceneGraph reference docs are vendored as
a git submodule (rokudev/dev-doc, branch v2.0) at
external/dev-doc. The reference pages live under external/dev-doc/docs/REFERENCES/
(Markdown with YAML frontmatter). They are the authoritative spec for what the behavior
should be — the brs-engine code is how we simulate it. Reach for this skill whenever a
task involves a missing, incomplete, or wrong-looking BrightScript/SceneGraph feature, and
before claiming a feature "matches Roku."
In this skill $REF means external/dev-doc/docs/REFERENCES.
The submodule must be initialized: if $REF is empty/missing, run
git submodule update --init external/dev-doc. It is reference only — never make
build/runtime code depend on it. If it still can't be fetched, say so and fall back to
https://developer.roku.com/docs/references/ (or skip the lookup).
When to use
- Implementing or fixing a
roXxx component / ifXxx interface method.
- Adding or correcting a SceneGraph node (fields, defaults, behavior).
- Implementing a global function (Math/String/Utility/Runtime) or language feature.
- Verifying argument counts, types, return values, defaults, or event semantics.
- Checking whether an API is deprecated.
Where things live (and where to implement them)
All paths below are relative to $REF (= external/dev-doc/docs/REFERENCES).
| Reference glob |
Topic |
Source to edit |
$REF/brightscript/components/roXxx.md |
Component overview + supported interfaces/events |
src/core/brsTypes/components/RoXxx.ts (register in BrsObjects.ts) |
$REF/brightscript/interfaces/ifXxx.md |
Method signatures, args, returns, defaults |
methods on the component, grouped under the ifXxx key in registerMethods — not a standalone type (see "Interfaces are method grouping" below) |
$REF/brightscript/events/roXxxEvent.md |
Event objects from roMessagePort |
the matching event component |
$REF/brightscript/language/*.md |
Statements, types, errors, #if, format strings, reserved words, global functions |
src/core/lexer/, parser/, preprocessor/, stdlib/ |
$REF/scenegraph/**/<node>.md |
SceneGraph node fields + behavior (by category) |
src/extensions/scenegraph/nodes/<Node>.ts |
$REF/scenegraph/xml-elements/*.md, component-functions/*.md |
Component XML + init/onKeyEvent |
src/extensions/scenegraph/parser/, factory/ |
$REF/deprecated-apis.md |
Deprecated APIs — check before relying on one |
n/a |
Filenames are lowercase, no spaces (e.g. rovideoplayer.md, ifsgnodefield.md,
renderable-nodes/rectangle.md). Files are Markdown: a YAML frontmatter block
(title, excerpt, …) at the top, ## headings, GitHub-style pipe tables for fields/
methods, fenced or double-backtick code samples, and cross-links written as
[label](doc:slug) (the slug is the target file's basename without .md).
How to look up
- Find the file. Map the BrightScript name to a path with the table above. If unsure
of the category for a SceneGraph node, search by filename:
REF=external/dev-doc/docs/REFERENCES
find "$REF/scenegraph" -iname '*<node>*'
find "$REF" -iname '*<name>*'
- Read it. A component file lists its supported
ifXxx interfaces (as [ifXxx](doc:ifxxx)
links) — follow those to the interfaces/ files for the actual method signatures. A node
file's Fields table (Field / Type / Default / Access Permission / Description) is the
spec for the node's fields; note that base-class fields are inherited and documented
separately (the file says "Fields derived from the … base class can also be used").
- Grep across the corpus when you don't know where a method/field is defined:
grep -rin "getmessageport" "$REF/brightscript/interfaces/"
grep -rl "itemComponentName" "$REF/scenegraph/"
Applying it to the code
- Match names/types/defaults/access exactly. A node's
defaultFields entries should
mirror the reference Fields table (e.g. Rectangle's width/height are float
default 0.0, color is color default 0xFFFFFFFF). Field type strings and
default values in code should equal the doc's Type/Default columns.
- Respect inheritance. If the doc says a node
Extends Group, the TS class should
extend the matching base and setExtendsType(name, SGNodeType.Group) — only declare
fields the doc adds beyond the base.
- Interfaces drive method surfaces, but don't become types. Use
ifXxx.md to get the
correct method names, arg order, optional args, and return types — then implement those
methods on the component and register them under the ifXxx key in
registerMethods({ ifXxx: [...] }). Do not create a new ifXxx class just because
the docs list one. See "Interfaces are method grouping" below.
- Cross-check before saying "done." When verifying a fix, re-read the relevant
reference and confirm signatures, defaults, and edge cases (and that the API isn't in
deprecated-apis.md) actually agree with the implementation.
Interfaces are method grouping, not separate types
The reference's ifXxx files describe Roku's interfaces, but this codebase does not
implement one type per interface. Follow the existing pattern:
- A component implements its methods (mostly inline on the class) and registers them
with
registerMethods({ ifXxx: [callable, ...] }). The ifXxx key is just a label that
mirrors the docs — there is no ifXxx contract being satisfied.// RoVideoPlayer.ts — methods defined inline, grouped under interface-name keys
this.registerMethods({
ifVideoPlayer: [this.play, this.stop, this.setContentList, /* ... */],
ifHttpAgent: [ifHttpAgent.addHeader, ifHttpAgent.setHeaders, /* ... */],
});
src/core/brsTypes/interfaces/ holds only a small, deliberate set of shared helper
classes (IfArray, IfEnum, IfHttpAgent, IfList, IfMessagePort, IfSocket,
IfToStr, IfDraw2D, …) — abstract/shared method bundles that exist purely to reduce
duplication when several components expose the same interface. Instantiate one with the
owning component and spread its callables into registerMethods:const ifArray = new IfArray(this);
this.registerMethods({ ifArray: [ifArray.peek, ifArray.pop, /* ... */] });
- Decision rule when adding a method/interface to a component:
- Shared by multiple components → add it to (or reuse) a helper in
interfaces/.
- Specific to one component → define it inline on that component class.
- Either way, register it under the matching
ifXxx key. Do not add a new file in
interfaces/ just to mirror a documented interface that only one component uses.
Wiring reminders (see CLAUDE.md for full detail)
- New component: implement
RoXxx.ts, register it in
src/core/brsTypes/components/BrsObjects.ts.
- New SceneGraph node: add to the
SGNodeType enum in
src/extensions/scenegraph/nodes/index.ts, create nodes/<Node>.ts, and wire it into
SGNodeFactory.createNode's switch in factory/NodeFactory.ts.
Source: lvcabral/brs-engine — distributed by TomeVault.
1---2name: brs-reference3description: Look up Roku's official BrightScript/SceneGraph spec in the external/dev-doc submodule (docs/REFERENCES/) when implementing, fixing, or verifying an interpreter feature — components (roXxx), interfaces (ifXxx), events, SceneGraph nodes, global functions, or language behavior. Use it to confirm exact method signatures, node field names/types/defaults/access, and event semantics so simulated behavior matches a real Roku device. Use when this capability is needed.4---56# brs-reference78Roku's **official**, open-sourced BrightScript + SceneGraph reference docs are vendored as9a git submodule ([rokudev/dev-doc](https://github.com/rokudev/dev-doc), branch `v2.0`) at10`external/dev-doc`. The reference pages live under **`external/dev-doc/docs/REFERENCES/`**11(Markdown with YAML frontmatter). They are the authoritative spec for *what the behavior12should be* — the brs-engine code is *how we simulate it*. Reach for this skill whenever a13task involves a missing, incomplete, or wrong-looking BrightScript/SceneGraph feature, and14before claiming a feature "matches Roku."1516In this skill `$REF` means `external/dev-doc/docs/REFERENCES`.1718> The submodule must be initialized: if `$REF` is empty/missing, run19> `git submodule update --init external/dev-doc`. It is **reference only** — never make20> build/runtime code depend on it. If it still can't be fetched, say so and fall back to21> <https://developer.roku.com/docs/references/> (or skip the lookup).2223## When to use2425- Implementing or fixing a `roXxx` component / `ifXxx` interface method.26- Adding or correcting a SceneGraph node (fields, defaults, behavior).27- Implementing a global function (Math/String/Utility/Runtime) or language feature.28- Verifying argument counts, types, return values, defaults, or event semantics.29- Checking whether an API is deprecated.3031## Where things live (and where to implement them)3233All paths below are relative to `$REF` (= `external/dev-doc/docs/REFERENCES`).3435| Reference glob | Topic | Source to edit |36| --- | --- | --- |37| `$REF/brightscript/components/roXxx.md` | Component overview + supported interfaces/events | `src/core/brsTypes/components/RoXxx.ts` (register in `BrsObjects.ts`) |38| `$REF/brightscript/interfaces/ifXxx.md` | Method signatures, args, returns, defaults | methods on the component, grouped under the `ifXxx` key in `registerMethods` — **not** a standalone type (see "Interfaces are method grouping" below) |39| `$REF/brightscript/events/roXxxEvent.md` | Event objects from `roMessagePort` | the matching event component |40| `$REF/brightscript/language/*.md` | Statements, types, errors, `#if`, format strings, reserved words, global functions | `src/core/lexer/`, `parser/`, `preprocessor/`, `stdlib/` |41| `$REF/scenegraph/**/<node>.md` | SceneGraph node fields + behavior (by category) | `src/extensions/scenegraph/nodes/<Node>.ts` |42| `$REF/scenegraph/xml-elements/*.md`, `component-functions/*.md` | Component XML + `init`/`onKeyEvent` | `src/extensions/scenegraph/parser/`, `factory/` |43| `$REF/deprecated-apis.md` | Deprecated APIs — check before relying on one | n/a |4445Filenames are lowercase, no spaces (e.g. `rovideoplayer.md`, `ifsgnodefield.md`,46`renderable-nodes/rectangle.md`). Files are Markdown: a YAML frontmatter block47(`title`, `excerpt`, …) at the top, `##` headings, GitHub-style pipe tables for fields/48methods, fenced or double-backtick code samples, and cross-links written as49`[label](doc:slug)` (the slug is the target file's basename without `.md`).5051## How to look up52531. **Find the file.** Map the BrightScript name to a path with the table above. If unsure54 of the category for a SceneGraph node, search by filename:55 ```bash56 REF=external/dev-doc/docs/REFERENCES57 find "$REF/scenegraph" -iname '*<node>*'58 find "$REF" -iname '*<name>*'59 ```602. **Read it.** A component file lists its supported `ifXxx` interfaces (as `[ifXxx](doc:ifxxx)`61 links) — follow those to the `interfaces/` files for the actual method signatures. A node62 file's **Fields** table (Field / Type / Default / Access Permission / Description) is the63 spec for the node's fields; note that base-class fields are inherited and documented64 separately (the file says "Fields derived from the … base class can also be used").653. **Grep across the corpus** when you don't know where a method/field is defined:66 ```bash67 grep -rin "getmessageport" "$REF/brightscript/interfaces/"68 grep -rl "itemComponentName" "$REF/scenegraph/"69 ```7071## Applying it to the code7273- **Match names/types/defaults/access exactly.** A node's `defaultFields` entries should74 mirror the reference Fields table (e.g. Rectangle's `width`/`height` are `float`75 default `0.0`, `color` is `color` default `0xFFFFFFFF`). Field `type` strings and76 default values in code should equal the doc's Type/Default columns.77- **Respect inheritance.** If the doc says a node `Extends Group`, the TS class should78 extend the matching base and `setExtendsType(name, SGNodeType.Group)` — only declare79 fields the doc adds beyond the base.80- **Interfaces drive method surfaces, but don't become types.** Use `ifXxx.md` to get the81 correct method names, arg order, optional args, and return types — then implement those82 methods on the **component** and register them under the `ifXxx` key in83 `registerMethods({ ifXxx: [...] })`. Do **not** create a new `ifXxx` class just because84 the docs list one. See "Interfaces are method grouping" below.85- **Cross-check before saying "done."** When verifying a fix, re-read the relevant86 reference and confirm signatures, defaults, and edge cases (and that the API isn't in87 `deprecated-apis.md`) actually agree with the implementation.8889## Interfaces are method grouping, not separate types9091The reference's `ifXxx` files describe Roku's interfaces, but this codebase does **not**92implement one type per interface. Follow the existing pattern:9394- A component implements its methods (mostly **inline** on the class) and registers them95 with `registerMethods({ ifXxx: [callable, ...] })`. The `ifXxx` key is just a label that96 mirrors the docs — there is no `ifXxx` contract being satisfied.97 ```ts98 // RoVideoPlayer.ts — methods defined inline, grouped under interface-name keys99 this.registerMethods({100 ifVideoPlayer: [this.play, this.stop, this.setContentList, /* ... */],101 ifHttpAgent: [ifHttpAgent.addHeader, ifHttpAgent.setHeaders, /* ... */],102 });103 ```104- `src/core/brsTypes/interfaces/` holds only a **small, deliberate set** of shared helper105 classes (`IfArray`, `IfEnum`, `IfHttpAgent`, `IfList`, `IfMessagePort`, `IfSocket`,106 `IfToStr`, `IfDraw2D`, …) — abstract/shared method bundles that exist purely to **reduce107 duplication** when several components expose the same interface. Instantiate one with the108 owning component and spread its callables into `registerMethods`:109 ```ts110 const ifArray = new IfArray(this);111 this.registerMethods({ ifArray: [ifArray.peek, ifArray.pop, /* ... */] });112 ```113- **Decision rule when adding a method/interface to a component:**114 - Shared by multiple components → add it to (or reuse) a helper in `interfaces/`.115 - Specific to one component → define it inline on that component class.116 - Either way, register it under the matching `ifXxx` key. **Do not** add a new file in117 `interfaces/` just to mirror a documented interface that only one component uses.118119## Wiring reminders (see CLAUDE.md for full detail)120121- New component: implement `RoXxx.ts`, register it in122 `src/core/brsTypes/components/BrsObjects.ts`.123- New SceneGraph node: add to the `SGNodeType` enum in124 `src/extensions/scenegraph/nodes/index.ts`, create `nodes/<Node>.ts`, and wire it into125 `SGNodeFactory.createNode`'s switch in `factory/NodeFactory.ts`.126127---128> Source: [lvcabral/brs-engine](https://github.com/lvcabral/brs-engine) — distributed by [TomeVault](https://tomevault.io).129<!-- tomevault:4.0:skill_md:2026-07-04 -->