--- name: brs-reference description: 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. --- # brs-reference Roku's **official**, open-sourced BrightScript + SceneGraph reference docs are vendored as a git submodule ([rokudev/dev-doc](https://github.com/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 > (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/**/.md` | SceneGraph node fields + behavior (by category) | `src/extensions/scenegraph/nodes/.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 1. **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: ```bash REF=external/dev-doc/docs/REFERENCES find "$REF/scenegraph" -iname '**' find "$REF" -iname '**' ``` 2. **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"). 3. **Grep across the corpus** when you don't know where a method/field is defined: ```bash 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. ```ts // 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`: ```ts 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 AGENTS.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/.ts`, and wire it into `SGNodeFactory.createNode`'s switch in `factory/NodeFactory.ts`.