This release brings 86+ improvements and fixes, focused on hardening the multi-threaded SceneGraph runtime and adding real network I/O. The engine gains fully functional roStreamSocket (TCP) and roDataGramSocket (UDP) support on the Node.js/CLI package, ECP sgrendezvous rendezvous tracking, and a --log-level CLI flag for quieter or more verbose console output. The SceneGraph extension's renderNode is now split into separate layout and paint passes that prune settled subtrees for a major performance gain, cross-thread Task handling is hardened (script-scope m, m.global/m.top references, findNode(), field sync and pre-launch port delivery all now survive a Task launch correctly), and dozens of focus, layout and rendering fixes land across LayoutGroup, PosterGrid, RowList, ArrayGrid, TextEditBox, ScrollingLabel, TimeGrid, Animation and the Dynamic Keyboards. A preliminary roAnimatedImage/AnimatedImage implementation adds animated WebP and Lottie playback ahead of Roku OS 15.3's official documentation. The browser API adds frame-change notifications with direct display-buffer access and a loading startup event. Read the full release notes below for more details.
Release Changes
Core Engine
- (brs) Memoize text measurement per
roFontinstance by @lvcabral in #1112 - (brs) Build
roString's methods on first access instead of per instance by @lvcabral in #1113 - (draw2d) Fixed three 9-patch sizing bugs —
Posterdisplay modes, marker parsing, and mid-render re-measure by @lvcabral in #1128 - (brs) Added a
logLevelparameter to filter output messages inOutputProxyby @lvcabral in #1146 - (brs) Boxed
callFunc()arguments the wayNode.get()already does, with regression tests by @lvcabral in #1150 - (brs) Support the
roRegex"x"(extended/free-spacing) flag by @lvcabral in #1159 - (brs) Real UDP send/receive/broadcast for
roDataGramSocketon the Node.js/CLI package by @lvcabral in #1164 - (brs) Implemented real TCP support for
roStreamSocketon the Node.js/CLI package by @lvcabral in #1170 - (draw2d) Made
blendColor's multiply a true multiply instead of fabricating one by @lvcabral in #1173 - (brs) Implemented
roAnimatedImagefor animated WebP/Lottie playback, a preliminary build ahead of Roku OS 15.3's published spec by @lvcabral in #1182
Browser API
- (api) Added frame notification (
setFrameNotify) and direct display-buffer access (getDisplayBuffer) by @lvcabral in #1149 - (api) Preserve rendezvous tracking state across resets in the shared array by @lvcabral in #1163
- (api) Added the
loadingevent, triggered on app startup by @lvcabral in #1176
Node.js Library and CLI
- (cli) Resolve locale-relative manifest icon and splash paths by @lvcabral in #1089
- (cli) Notify the user when a new
brs-nodeversion is published by @lvcabral in #1103 - (cli) Expose SceneGraph rendezvous tracing to the CLI and browser API by @lvcabral in #1104
- (cli) Let the ECP server bind a port other than 8060 by @lvcabral in #1106
- (cli) Add
sfxto the valid message types ignored inhandleStringMessageby @lvcabral in #1107 - (cli) Terminate the app when a
Taskthread hits an uncaught error by @lvcabral in #1111 - (cli) Added a
--log-levelflag and aloglevelREPL command by @lvcabral in #1141 - (cli) Implemented the ECP
sgrendezvousrendezvous-tracking endpoints by @lvcabral in #1148 - (cli) Upgraded
node-canvasto v4-rc2 and removed the whitespace-only text workaround by @lvcabral in #1166
SceneGraph Extension (brs-scenegraph release v0.4.0)
- (rsg) Defer init-time
focusedChildnotifications to the message loop by @lvcabral in #1090 - (rsg) Correct mid-render
boundingRect()measurement of composite nodes by @lvcabral in #1091 - (rsg) Carry a custom node's script-scope
macross threads by @lvcabral in #1092 - (rsg) Deliver a
Task's pre-launch port events to its thread by @lvcabral in #1093 - (rsg) Let
m.global.findNode()reach the scene tree by @lvcabral in #1094 - (rsg) Parent the global node to the
Sceneby @lvcabral in #1095 - (rsg) Keep
m.global's own descendants out of itsfindNode()search by @lvcabral in #1096 - (rsg) Resolve
findNode()against the executing component's scope by @lvcabral in #1097 - (rsg) Cross script-scope
mas live references, only on owner transfer by @lvcabral in #1098 - (rsg) Repair the release build broken by the
findNode()global check by @lvcabral in #1099 - (rsg) Reference
m.global's node fields in theTasklaunch payload by @lvcabral in #1100 - (rsg) Stop
findNode()searching a node that has no component ancestor by @lvcabral in #1101 - (rsg) Don't crash when a
Tasksets a node-valued field to invalid by @lvcabral in #1102 - (rsg) Made cross-thread
Taskfield sync and port observers work between threads by @lvcabral in #1105 - (rsg) Notify observing
Taskthreads when content held by a field changes by @lvcabral in #1108 - (rsg) Deliver a
Taskfield set made just before launch exactly once by @lvcabral in #1110 - (rsg) Time out a rendezvous only when the render thread stops running by @lvcabral in #1115
- (rsg) Split
renderNodeinto layout/paint passes and prune settled subtrees (major performance gain) by @lvcabral in #1120 - (rsg) Match device behavior for
LayoutGroup's enum fields, spacing and size by @lvcabral in #1122 - (rsg) Keep script-scope references to
global/topalive across aTasklaunch by @lvcabral in #1123 - (rsg) Resolve script-scope references into the
top/globalsubtrees onTasklaunch by @lvcabral in #1124 - (rsg) Stop a directional key on an empty
RowListfrom crashing the app by @lvcabral in #1125 - (rsg) Commit a focus change before notifying, and ignore a re-grab from a focus-loss observer by @lvcabral in #1127
- (rsg) Bind observer callback parameters the way a device does by @lvcabral in #1129
- (rsg) Normalize hex-string elements in
colorarrayfields by @lvcabral in #1130 - (rsg)
RowListhonorsvertFocusAnimationStylewhen scrolling rows by @lvcabral in #1131 - (rsg) Honor
clippingRecton every renderable node by @lvcabral in #1133 - (rsg) Report per-row extents in a grid's
boundingRectby @lvcabral in #1134 - (rsg) Made
Animationcontrolconform to a device by @lvcabral in #1136 - (rsg) Honor per-row layout in
LabelListand rotate every node's translation by @lvcabral in #1137 - (rsg) Match a device's
PosterGridextent by @lvcabral in #1138 - (rsg) Match Roku's console format for rendezvous tracing by @lvcabral in #1140
- (rsg) Report a grid item's sub-rect as the bare item component by @lvcabral in #1142
- (rsg) Report a
PosterGrid's asymmetric vertical outset by @lvcabral in #1144 - (rsg) Report an alias field's own name in observer events by @lvcabral in #1151
- (rsg) Add missing documented
ContentNodefields by @lvcabral in #1152 - (rsg)
ScrollingLabelreports the fullmaxWidthas its measured width by @lvcabral in #1154 - (rsg) Fixed a
PosterGridcaption placement regression from #1144 by @lvcabral in #1156 - (rsg) Fixed the
Overhangdefault logo overlapping the title/divider on a resolution-mismatched device by @lvcabral in #1157 - (rsg)
LayoutGroupcounts a hidden child's height in a vertical stack by @lvcabral in #1158 - (rsg) Fixed cross-thread
AppendChildrenduplicating a node instead of moving it by @lvcabral in #1160 - (rsg) Fixed stale item visuals after an in-place
ArrayGrid/RowListcontent reorder by @lvcabral in #1161 - (rsg) Fixed
TimeGridcontent-mutation staleness, navigation, and loading feedback by @lvcabral in #1162 - (rsg) Fixed
TextEditBoxtext/cursor mispositioning with a custombackgroundUriby @lvcabral in #1165 - (rsg) Fixed
TextEditBoxdiscarding the app-provided height with a custom background by @lvcabral in #1167 - (rsg) Update
currFocusRow/currFocusColumnbeforeitemFocusedfires by @lvcabral in #1168 - (rsg) Normalize key actions/icons and add a
keySelected()handler for the Dynamic Keyboards by @lvcabral in #1169 - (rsg) Stop painting fully transparent subtrees, and honor a 0-alpha blend color by @lvcabral in #1172
- (rsg) Gave
ArrayGridafocusRecthook so subclasses specialize geometry only by @lvcabral in #1174 - (rsg) Distinguish a layout pass from a paint frame whose drawing was suppressed by @lvcabral in #1175
- (rsg) Drop a backwards focus steal raised via a container redirect by @lvcabral in #1177
- (rsg) Apply the
scalefield to drawn content, bounding rect, and remaining text nodes by @lvcabral in #1179 - (rsg) Implemented
PosterloadDisplayMode="limitSize"by @lvcabral in #1180 - (rsg) Implemented the SceneGraph
AnimatedImagenode, a preliminary build ahead of Roku OS 15.3's published spec by @lvcabral in #1182)
Chores, Build and Dependencies
- (chore) Migrate the test runner from Jest to Vitest by @lvcabral in #1087
- (docs) Finish the Jest-to-Vitest cleanup and fix stale http links by @lvcabral in #1088
- (docs) Proposed splitting
renderNodeinto layout and paint passes by @lvcabral in #1114 - (docs) Split
CLAUDE.mdinto a core map plus on-demand deep dives by @lvcabral in #1116 - (chore) Removed the
BRS_PRUNE_VERIFYharness and updated docs by @lvcabral in #1121 - (chore) Saved several probe apps into
test/simulator/probesby @lvcabral in #1143 - (test) Added
LayoutGrouplayoutDirectionanditemSpacingsprobes by @lvcabral in #1145 - (chore) Split
cli.test.jsinto focused suites and de-flaked the Task-pool CLI test by @lvcabral in #1153 - Bump fast-uri from 3.1.4 to 3.1.5 by @dependabot[bot] in #1155
- (docs) Updated limitations for Roku SceneGraph and network components by @lvcabral in #1171
Full Changelog: v2.3.0...v2.4.0