2.19.0

⚠️ Upgrade Notes

  • Upgrade FlexGrid 3 to 3.4.0 with this release. @roku-sdk/flex-grid 3.1.0–3.3.0 import the removed @roku-sdk/navigation/internal entry point (see Breaking Changes). Move @roku-sdk/flex-grid to 3.4.0 in the same change as the other @roku-sdk/* packages. FlexGrid 2.x is unaffected.
  • zod 4. @roku-sdk/ai and @roku-sdk/tooling now depend on zod ^4.6.6. zSkillEntry and zSkillManifest from @roku-sdk/ai are zod 4 schemas; code that composes them with zod 3 must move to zod 4.
  • solid-js 1.9.17 or later. @roku-sdk/solid now requires solid-js ^1.9.17. If your app declares its own solid-js, raise it to match.
  • Fractional bounds in @roku-sdk/device-test-client. parseBounds and AppUiNode.bounds return decimal values instead of a zero rect. Bounds checks on 720p devices (for example 899.99994 for 900) may need a tolerance.
  • FlexGrid guide anchors changed. Section headings are no longer numbered, so links such as #6-nested-grids become #nested-grids.

💥 Breaking Changes

  • @roku-sdk/navigation/internal is removed. Use @roku-sdk/navigation/focus-relay, which exports useFocusRelayTarget, createFocusRelay, FocusRelayProvider and the FocusRelay and FocusRelayTarget types. Replace FocusBoundaryContext.Provider with FocusRelayProvider. See rsg-sdk/external/packages/navigation/BREAKING_CHANGES.md.
  • @roku-sdk/device-test-client/internal/* moves to ./support/*. Change /internal/deploy, /internal/constants and /internal/paths to /support/.... ARTIFACT_FILE is now exported from the package root.
  • CLI-only config types move to @roku-sdk/tooling. BuildConfig, StartDevConfig, BuildConfigType, CliOptionVariant and templateFunc are no longer exported from @roku-sdk/sdk-config. Type pipeline hooks against CommonBuildConfig. Apps that only use RokuConfig need no change.

🗑️ Deprecations

These are removed in the next minor release.

  • @roku-sdk/navigation: focusIdLabel, createKeyPressCaptureRegistry, createBoundaryState, BoundaryStateOptions, RegisteredHandlers and KeyPressCaptureRegistry. Use FocusBoundary, useFocusable and useFocusActions.
  • @roku-sdk/sdk-config: InternalRokuManifestEntries. Use RokuManifestEntries.

✨ New Features

  • @roku-sdk/text-layout (new package): line breaking, word wrapping and ellipsis for labels, given a width function. Exports layoutLabel, layoutLabelInFont, wrapText, ellipsizeText and scalesFor.
  • Font readiness. whenFontReady(font, { signal }) resolves when a <font> can be measured; createFontReady(fontAccessor, key?) is the reactive form. Both are in @roku-sdk/runtime/font and @roku-sdk/rsg-ts/runtime, and replace timer-based waits before measuring text.
  • rk dev --watch reloads config. Saving roku-config.ts or roku-dev-config.ts rebuilds and reinstalls with the new settings, without a restart. Changes to outDir still need a restart.
  • rk dev --watch rebuild key. Press r for a full rebuild (clean, build and install). This also works when rk dev runs through rk server.
  • Faster repeat builds. rk build and rk dev type-check incrementally and skip unchanged XML type generation, about 20–25% faster on repeat release builds.
  • Video track callbacks. Typed onAvailableAudioTracks, onCurrentAudioTrack, onAvailableSubtitleTracks and onCurrentSubtitleTrack props, with IVideoAudioTrack and IVideoSubtitleTrack payload types.
  • hasReturnFootprint. useFocusable() and useFocusActions() report the item focus will return to when its boundary becomes active again.
  • Effect gradient warnings. Development builds warn when Effect gradient colors or stops are invalid, instead of silently not rendering.
  • RkClient.holdKey(key, holdMs) in @roku-sdk/device-test-client holds a key for a set time.

🐛 Bug Fixes

  • this, arguments and super now work inside loop bodies whose loop variable is captured by a closure.
  • rk reports installer error pages returned with HTTP 200 as a failed deploy, instead of claiming success and relaunching the previous build.
  • FlexGrid 3: tapping the opposite direction during the settle after a released hold now takes effect instead of being overridden.
  • @roku-sdk/device-test-client: more reliable app readiness detection, retries for sideloads that fail to start, and recovery from a stalled log stream.
  • Dependency updates (solid-js, zod, express, body-parser) clear the outstanding pnpm audit advisories.

📚 Examples

  • focus-boundary adds a Focus Footprint demo for hasReturnFootprint.
  • runtime-showcase and the Cowboy TV FlexGrid example use the new font-readiness APIs.

📚 Documentation

  • Docs revised against the Roku documentation style guide, with many guides restructured.
  • Getting started now walks through the two-cowboys example, and the overview covers migrating a BrightScript app to TypeScript incrementally.
  • rk reference pages show option defaults, allowed values and examples.

Note: the SDK's XML FocusBoundaryBase is renamed FocusBoundaryBaseShim. On firmware with a native FocusBoundaryBase, the native component is used; otherwise the shim is swapped in at runtime.

2.18.0

⚠️ Upgrade Notes

RemoteKeyName now autocompletes known keys. The type was RemoteKey | string, which collapsed to string and gave no autocomplete or typo checking. It is now KnownRemoteKeyName | RemoteKeyNameCompat, where KnownRemoteKeyName is RemoteKey | \${RemoteKey}`. The deprecated RemoteKeyNameCompat (string & ) keeps arbitrary strings compiling for now, so existing code is unaffected. A future major release will remove the compatibility alias and make RemoteKeyNamethe closed union, so start usingRemoteKeymembers or known key literals.@roku-sdk/interfacesalso exports a newRemoteKeyEvent ({key: RemoteKeyName; press: boolean}), which the packages and examples now use in place of ad hoc {key: string; press: boolean}` types.

Focus-path context types were renamed. In @roku-sdk/navigation, FocusPathCtx is now FocusPathContext and FocusPathContextValue is now IFocusPathContext, matching the ScreenControllerContext / IScreenControllerContext pattern. The old names remain exported as deprecated aliases and will be removed in 3.0. On @roku-sdk/navigation/internal, FocusBoundaryCtx is a deprecated alias for FocusBoundaryContext; the former FocusBoundaryContext interface has no alias because that name is now the context value, and the type is IFocusBoundaryContext. Apps do not normally read or provide this context. See rsg-sdk/external/packages/navigation/BREAKING_CHANGES.md.

@roku-sdk/flex-grid-3 deprecates implementation-only exports. The store helpers, engine and navigation controller factories, plugin-resolution helpers, Bob geometry helpers and the legacy root FocusHighlightConfig remain available throughout 3.x but are scheduled for removal in the next major release. The geometry helpers (buildUniformCumX, buildCumY, computeScrollYForRow and related) move to @roku-sdk/flex-grid/geometry; import them from there. _resetGlobalHooksForTest from @roku-sdk/flex-grid/perf is deprecated as a test-only export. Use createFlexGrid, FlexGridHandle, the public focus strategies and the plugin factories instead. The pool-size helpers (computeUniformPoolSize, computeVariablePoolSize, computeDataRow, PoolSizeResult) are no longer exported. See rsg-sdk/external/packages/flex-grid-3/BREAKING_CHANGES.md.

rk validates build and dev options more strictly. Conflicting or unknown options to rk build and rk dev are now rejected before the server fast path is used, with consistent exit codes and wording across presets. The rk server build and dev routes reject a raw --config or --build-type that repeats a structured field, has no value, or conflicts with it, returning 400 VALIDATION_ERROR. Scripts that relied on the old, silently accepted combinations will see errors.

rk refuses to clean unsafe output directories. cleanOutDir now rejects an output directory that is a symlink or has a symlinked parent, and requires a root directory for cleanup. Symlinks to empty directories inside the output are handled correctly. If your outDir is reached through a symlink, point it at the real path.

The @roku-sdk/runtime ./art-mode export is removed. Its source never shipped in the package, so the entry resolved to a missing file.

💥 Breaking Changes

<tween> follows the native Tween contract. toY and delay are removed from the <tween> intrinsic (ITweenProps, ITweenCoreProps) and from the @roku-sdk/flex-grid Tween wrapper (TweenProps). Pass targetVector={[x, y]} instead of targetValue plus toY. delay has no replacement; write the target from a timer if you need the wait. onAnimationState on the intrinsic now receives one [state, value] tuple, where value is a number or Vector2D; the FlexGrid Tween wrapper keeps its (state, value) callback.

axis="both" is removed; use axis="all". Vector settlement now chooses one whole [x, y] candidate from proposedStops and applies it to every component the axis owns, so a diagonal glide lands on both coordinates instead of leaving the minor axis where it was. For a vector field under "all", proposedStops is [number, number][]; float fields and "x"/"y" keep number[]. Entries of the wrong shape are skipped and logged. In FlexGrid, GridPluginInternals.focus.settleStop() now returns [number, number][] (including the focused row's Y offset) so it can be passed straight to proposedStops.

Migration details are in @roku-sdk/components and @roku-sdk/flex-grid BREAKING_CHANGES.md and the new Tween value-shape contract page under core concepts.

✨ New Features

Tween moves to @roku-sdk/components, with native node support

Tween now lives in @roku-sdk/components; @roku-sdk/flex-grid re-exports it, so existing FlexGrid imports keep working. On firmware that reports the tween feature (hasFeature("tween")), <tween> renders the native Tween node. Elsewhere, the new @roku-sdk/compat package, injected by the build, supplies a BrightScript stand-in with the same field contract. With app.compat: false, creating <tween> on firmware without the feature throws an error naming it. No current firmware reports the feature yet, so devices use the stand-in for now.

@roku-sdk/runtime — hasFeature and Heap Graph Capture

hasFeature(key) reports whether the firmware supports a feature, caching each answer for the app's lifetime. It returns false for unknown keys and where roku.hasFeature is unavailable, including older firmware and non-device environments. Feature strings are defined in firmware.

perfetto.captureHeapGraph?.() captures a heap graph snapshot into the active Perfetto trace session. It is optional for backward compatibility, does nothing when no trace session is active, requires Roku OS 16.1 and is not supported on Liberty devices.

rk — Hermes Bytecode Sideload Warning

rk sideload, rk dev, the sideload_app MCP tool and the sideload build plugin now warn when the manifest's ts_path points at Hermes bytecode (.hbc), which devices do not run as a debuggable bundle. The warning is reported as a warning, not an error.

Other Additions

  • rk cdp breakpoints and source retrieval accept absolute, project-relative or working-directory-relative paths. An unmapped line is now distinguished from a file outside the bundle ("no compiled code at or after this line").
  • rk server stop finds the running server through .roku/rk-server.json instead of assuming the derived port, and reports a stale port file rather than dialling a port that now belongs to another process. rk server start, stop and status reject unknown options.
  • rk mcp --help prints help instead of starting the stdio server.
  • RK_DEVICE_IP alone is enough for @roku-sdk/device-test-client: the device is looked up in the stored devices by that IP and its stored password is used. RK_DEVICE_PASSWORD without an IP is still an error.
  • rk dev --host now honours ROKU_DEV_PASSWORD, and target-device password resolution is validated consistently.
  • @roku-sdk/dev-tools Jest setup logs high memory use only when JEST_LOG_MEMORY is set, and no longer prints per-file peak memory lines.

🐛 Bug Fixes

  • FlexGrid 3 row posters no longer overlap the row title or the Bob-in-the-middle area, and setRowHeight treats a missing row height as cellSize[1].
  • rk MCP no longer starts a stdio session when only help was requested.
  • @roku-sdk/tooling package.json main/types now point at files that ship, so legacy (node10-style) resolution finds the types.
  • Slideshow's internal animation component is renamed SlideshowTween, so it no longer collides with the native Tween node name.

📚 Examples

All examples now invoke rk directly in their package.json scripts instead of npx rk, removing "Unknown env config" warnings under pnpm. The FlexGrid, FocusBoundary, showcase, pitfalls and slideshow examples use RemoteKeyEvent.

pooled-item-row drops its private tween component and uses the shared Tween. Fantasy TV's scale tweens use targetVector.

📚 Documentation

The rk reference is now generated from command specs and route registries covering build, dev, server, mcp, cdp, dap, debug, logs, perfetto, device, create, setup, decode-stack, package, gen-types and version, including HTTP route pages (with SSE streams and error envelopes) and an environment-variable page. Hand-written option tables now link to it. Getting-started, overview, tutorial and example pages were consolidated into the standing documentation (guides, core concepts, advanced) and the directory-layout page was rewritten for registry installs. Packages that had empty npm pages (@roku-sdk/common, @roku-sdk/dev-tools, @roku-sdk/flex-grid, @roku-sdk/interfaces, @roku-sdk/native, @roku-sdk/sdk-config, @roku-sdk/solid, @roku-sdk/testing-library, @roku-sdk/tooling, @roku-sdk/ts-core) gained READMEs.

A new Tween value-shape contract page under core concepts documents target and proposedStops shapes per field type and axis.


Did this page help you?