Showcase app: AI reference map

Reference map of reusable components, patterns, contexts, and utilities in the Showcase app

Purpose: This document is a structured reference for AI assistants working on the Showcase app. It maps reusable components, architectural patterns, contexts, and utilities to their source files and usage examples. You can use this document to find existing code instead of writing new implementations.

All paths are relative to the repository root.

Table of contents

The following list links to each section of this reference.

  1. App shell and navigation
  2. Context providers (state management)
  3. Reusable UI components
  4. Showcase utilities and data
  5. Drawing styles and theming
  6. Architectural patterns
  7. Dialog patterns
  8. List and grid scene patterns
  9. Media playback patterns
  10. Compiled (BRS/XML) components

1. App shell and navigation

These components provide the app shell and navigation.

ShowcaseApp (root component)

The root entry point of the app is ShowcaseApp.

  • Name: ShowcaseApp
  • When to use: The root entry point of the entire app. When you need to understand the provider hierarchy or add a new global provider, start here. Extends FocusBoundaryBase and wraps the provider tree in RootFocusBoundary (bridge fields: keyEvent, focusActive, handledKeys, focusPath). Provider hierarchy: RootFocusBoundary → ResolutionProvider → ScreenRegistryProvider (which mounts ScreenControllerProvider internally) → MenuPathControllerProvider → FullscreenVideoProvider → DialogProvider.
  • Implementation file: examples/showcase/src/components/showcase-app.tsx
  • Usage example: examples/showcase/src/index.ts (registers ShowcaseApp via declareTsComponent)
  • Focus reference: examples/focus-boundary/src/components/focus-boundary-app.tsx

MainScene (scene & dialog registry)

The MainScene component registers every scene and dialog factory.

  • Name: MainScene
  • When to use: When registering a new scene or dialog. All scene factories and dialog factories are registered here in SCENES and DIALOGS arrays. This is the single place where scene IDs are mapped to components.
  • Implementation file: examples/showcase/src/components/main-scene.tsx
  • Usage example: examples/showcase/src/components/showcase-app.tsx (rendered inside provider tree)

MenuScene (fallback / home screen)

The home screen of the app is MenuScene.

  • Name: MenuScene
  • When to use: When setScreen(null) is called or no scene is active. This is the home screen. It renders the MainMenu inside a PanelSet wrapped by SceneWrapper, inside a nested FocusBoundary that handles app-level Back (exit dialog) via onUnhandledKey. You must not thread FocusBoundary through PanelSet and ListPanel slides; panel menus stay on SceneGraph-native focus (LabelList, jumpTo, slidingBack).
  • Implementation file: examples/showcase/src/components/menu-scene.tsx
  • Usage example: examples/showcase/src/components/showcase-app.tsx (passed as fallback to ScreenRegistryProvider)

MainMenu (top-level menu)

The root menu that the app renders inside MenuScene is MainMenu.

  • Name: MainMenu
  • When to use: When adding a new top-level showcase entry. Each item defines a title, optional sceneDialogId, and a getNextPanel factory for the info panel or submenu. The Keyboards entry opens KeyboardShowcase, whose items open fullscreen scenes for DynamicCustomKeyboard, DynamicKeyGrid, DynamicKeyboard, DynamicMiniKeyboard, National CustomKeyboard, and DynamicPinPad.
  • Implementation file: examples/showcase/src/components/main-menu.tsx
  • Usage example: examples/showcase/src/components/menu-scene.tsx (rendered inside PanelSet)
  • Usage example: examples/showcase/src/components/showcases/keyboard-showcase/index.tsx (extensible keyboard submenu)

SceneWrapper / BackSceneWrapper / SceneFocusBoundary

The SceneWrapper, BackSceneWrapper, and SceneFocusBoundary components provide the standard chrome and focus handling for fullscreen views.

  • Name: SceneWrapper, BackSceneWrapper, SceneFocusBoundary
  • When to use: When you need a fullscreen view with the standard Roku Overhang chrome (logo, clock, title, optional options text). SceneWrapper renders the Overhang header and passes children through. BackSceneWrapper wraps SceneWrapper in SceneFocusBoundary, which registers the active scene as the nested child of RootFocusBoundary via ACTIVE_REGION_REF and handles keys through onUnhandledKey (default: back → setScreen(null)). You can pass extra scene keys on BackSceneWrapper via onUnhandledKey (for example, options, OK, left/right). Props: title, showOptions, optionsText, showBackHint, onBack, onUnhandledKey, children. Every fullscreen scene must be wrapped in BackSceneWrapper.
  • Implementation file: examples/showcase/src/components/scene-wrapper.tsx, scene-focus-boundary.tsx
  • Usage example: examples/showcase/src/components/showcases/poster-showcase/poster-scene-showcase.tsx (BackSceneWrapper with title + showBackHint)
  • Usage example: examples/showcase/src/components/showcases/busy-spinner-showcase/busy-spinner-scene-showcase.tsx (onUnhandledKey={{ OK: onPress(toggle) }})

Focus region refs (ACTIVE_REGION_REF / REGION_SHELL_REF)

  • Name: ACTIVE_REGION_REF, REGION_SHELL_REF, RegionShellFocusable
  • When to use: ACTIVE_REGION_REF is the shared stable identity wired as initialFocus on RootFocusBoundary and focusId on each menu/scene nested FocusBoundary. Only one region is mounted at a time (menu or fullscreen scene). REGION_SHELL_REF + RegionShellFocusable provide a no-op virtual focus target inside SceneGraph-native regions so that onUnhandledKey can dispatch (PanelSet, RowList, and so on keep SceneGraph focus).
  • Implementation file: examples/showcase/src/components/focus-region-context.tsx, region-shell-focusable.tsx

SceneDialogMenu

The SceneDialogMenu component is a labeled list menu that can open scenes and dialogs.

  • Name: SceneDialogMenu
  • When to use: When you need a labeled list menu that can trigger both scene navigation and dialog opening. Wraps ListMenuPanel and adds ScreenRegistryContext + DialogContext integration: items with sceneDialogId switch scenes via setScreen, items with isDialog: true open dialogs via setDialog. Uses MenuPathControllerContext (jumpTo, saveMenuPath) for cursor restoration after Back; it does not use an imperative panelRef.focus(). Props: items (array of IListMenuPanelItem), slidingBack, panelSize, leftOnly, onItemSelected. You can use this instead of ListMenuPanel when items need to open scenes or dialogs.
  • Implementation file: examples/showcase/src/components/scene-dialog-menu.tsx
  • Usage example: examples/showcase/src/components/showcases/dialog-showcases/index.tsx (DialogShowcase menu)
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/index.tsx (ListAndGridShowcase menu)
  • Usage example: examples/showcase/src/components/showcases/keyboard-showcase/index.tsx (KeyboardShowcase menu)

ListMenuPanel

The ListMenuPanel component is a labeled list with drill-down panel navigation.

  • Name: ListMenuPanel
  • When to use: When you need a labeled list with drill-down panel navigation. Structurally it is a ListPanel containing a LabelList built from ContentNode children. When an item is focused, its getNextPanel factory is called to render the adjacent detail panel. Supports jumpTo for restoring focus position, hasNextPanel override, an optional info message Poster at the bottom, and callbacks for onItemFocused, onItemSelected, onFocusedChild. Props: items (array of IListMenuPanelItem), slidingBack, panelSize, leftOnly, gainFocus, messageText, and so on. You can use it for panel-only navigation menus (no scene/dialog switching).
  • Implementation file: examples/showcase/src/components/list-menu-panel.tsx
  • Usage example: examples/showcase/src/components/showcases/label-showcases/index.tsx (LabelShowcase submenu)
  • Usage example: examples/showcase/src/components/showcases/group-submenu.tsx (GroupSubmenu)

2. Context providers (state management)

These contexts and providers manage navigation, dialogs, and fullscreen video.

ScreenRegistryContext / ScreenRegistryProvider (app-level, id-based)

The ScreenRegistryContext context navigates screens by string ID.

  • Name: ScreenRegistryContext
  • When to use: Default choice for any showcase code that wants to address screens by string id. The provider holds a Map<string, () => JSX.Element> of screen factories and resolves ids before delegating to the underlying ScreenControllerContext. Mounted once at the app root (ScreenRegistryProvider); internally mounts a ScreenControllerProvider so the lower-level controller is also available throughout the tree. Key API:
    • registerScreen(id, factory) / deregisterScreen(id): add/remove screens (call in onMount/onCleanup).
    • setScreen(id | null) / pushScreen(id | null) / resetScreen(id | null): id-based navigation; unknown or null ids render the fallback.
    • popScreen(), getScreen(), onScreenCovered, onScreenUncovered: pass through to the underlying controller.
  • Implementation file: examples/showcase/src/components/screen-registry/screen-registry.tsx
  • Usage example: examples/showcase/src/components/scene-wrapper.tsx (BackSceneWrapper calls setScreen(null) on Back key)
  • Usage example: examples/showcase/src/components/scene-dialog-menu.tsx (calls setScreen on item selection)

ScreenControllerContext / ScreenControllerProvider (lower-level, factory-based)

The ScreenControllerContext context navigates screens by factory function.

  • Name: ScreenControllerContext
  • When to use: When you want to push/replace screens directly with factory functions (no string ids). Available throughout the showcase tree because ScreenRegistryProvider mounts a ScreenControllerProvider internally. You can useContext(ScreenControllerContext) anywhere. The screen-stack showcase uses this directly to push the next screen as a JSX factory; most other showcases prefer the higher-level ScreenRegistryContext. Key API:
    • pushScreen(factory | null) / setScreen(factory | null) / resetScreen(factory? | null): null (or omitted on resetScreen) renders the provider's fallback.
    • popScreen(), getScreen(), onScreenCovered, onScreenUncovered.
  • Implementation file: packages/navigation/src/screen-controller/screen-controller.tsx (imported as @roku-sdk/navigation)
  • Usage example: examples/showcase/src/components/showcases/screen-stack-showcase/screen-stack-base-scene.tsx (pushScreen(() => <ScreenStack1 />) on OK)

MenuPathControllerContext / MenuPathControllerProvider

The MenuPathControllerContext context saves and restores nested menu focus positions.

  • Name: MenuPathControllerContext
  • When to use: When a menu component needs to save and restore nested focus positions across scene transitions. The provider owns a createSignal<number[]> for the focused index path and an internal depth counter. Key API:
    • acquireMenuDepth() / releaseMenuDepth(): manages a nesting depth counter; each mounted menu claims one slot.
    • trackMenuFocus(depth, index): record the focused item index at a given nesting depth; truncates deeper entries when focus diverges.
    • saveMenuPath(): snapshot the current focus path into the menu index stack so it can be restored later.
    • getMenuIndexStack() / setMenuIndexStack(...): direct access to the saved index stack used by restorers.
  • Implementation file: examples/showcase/src/components/menu-path-controller-context.tsx
  • Usage example: examples/showcase/src/components/scene-dialog-menu.tsx (SceneDialogMenu tracks focus and restores it on back navigation)

DialogContext / DialogProvider

The DialogContext context manages modal dialogs.

  • Name: DialogContext
  • When to use: When you need a registry-based modal dialog manager with stack-based parent/child navigation. The provider holds a Map<string, (data?) => JSX.Element> of dialog factories and a signal-based dialog state stack. Key API:
    • registerDialog(id, factory) / deregisterDialog(id): add/remove dialog types (call in onMount/onCleanup).
    • setDialog(id, onClose, data?, parentId?): open a dialog by ID; onClose is called when the dialog reports completion.
    • closeDialog(params?): close the current dialog. If it is a child, restores the parent with _childCloseParams merged into its data. If root, calls onClose and clears.
    • openChildDialog(childId, childData, parentData): pushes a child dialog onto the stack; parent data is backed up and restored when child closes.
    • getDialogElement(): returns the current dialog JSX or null.
    • getDialogData<T>() / getParentDialogData<T>(): typed accessors for current/parent dialog data.
    • getChildCloseParams<T>(data): utility to extract _childCloseParams from data after a child closes.
  • Implementation file: examples/showcase/src/components/showcases/dialog-showcases/dialog-context.tsx
  • Usage example: examples/showcase/src/components/showcases/dialog-showcases/simple-dialog.tsx (uses closeDialog in onWasClosed)
  • Usage example: examples/showcase/src/components/property-chooser/property-chooser-dialog.tsx (uses openChildDialog for nested navigation)

FullscreenVideoContext / FullscreenVideoProvider

The FullscreenVideoContext context coordinates scene transitions to and from the fullscreen video player.

  • Name: FullscreenVideoContext
  • When to use: When you need to coordinate a scene transition to/from a fullscreen video player. The provider wraps ScreenRegistryContext.setScreen with video-specific state: a params signal (IFullscreenVideoParams: playlist, contentIndex, seekPosition) and a returnToScene signal. Key API:
    • openFullscreenVideo(params, returnToScene?): stores playback params, then calls setScreen("fullscreen-video-scene").
    • closeFullscreenVideo(): clears params, then calls setScreen(returnToScene) to navigate back.
    • getParams(): reactive accessor for the current playback params (null when inactive).
  • Implementation file: examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/fullscreen-video-context.tsx
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/time-grid-video-preview.tsx (opens fullscreen on program selection)

3. Reusable UI components

These components are reusable across showcases.

InfoPanel

The InfoPanel component is a titled rich-text panel with automatic overflow handling.

  • Name: InfoPanel
  • When to use: When you need a titled rich-text panel with automatic overflow handling. Structurally it is a Panel containing a Label title and a MultiStyleLabel body wrapped in a MaskGroup. It measures body content on mount via BoundingTracker: if text fits, it renders statically; if it overflows, it applies a gradient mask and a looping scroll Animation with Vector2DFieldInterpolator. Supports configurable panelSize, custom drawingStyles, and an optional "Press OK" call-to-action banner. Props: id, title, text, panelSize, drawingStyles, showOkMessage. The standard descriptive panel for all scene showcases, and reusable for any scrollable rich-text display.
  • Implementation file: examples/showcase/src/components/info-panel/info-panel.tsx
  • Usage example: examples/showcase/src/components/showcases/poster-showcase/poster-showcase.tsx (PosterPanel: narrow, with showOkMessage)
  • Usage example: examples/showcase/src/components/showcases/animation-showcase/animation-info-panel.tsx (AnimationInfoPanel: narrow, with showOkMessage)
  • Usage example: examples/showcase/src/components/showcases/dialog-showcases/simple-dialog-panel.tsx (SimpleDialogPanel: medium, with showOkMessage)

CodePanel

The CodePanel component renders text on a Poster background with a custom font.

  • Name: CodePanel
  • When to use: When you need a text block rendered on a Poster background with a custom font. Structurally it is a Poster (9-patch bitmap background) containing a Label with the Inconsolata monospaced font, padded content area, and configurable dimensions. Accepts translation, width, height, and text props. Used in list and grid scenes for live code snippets, and suitable for any styled text overlay on a poster background.
  • Implementation file: examples/showcase/src/components/code-panel.tsx
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx (reactive text on poster background showing current PosterGrid props)

TbdPanel

The TbdPanel component is a minimal placeholder panel with a styled message.

  • Name: TbdPanel
  • When to use: When you need a minimal placeholder panel with a styled message. Structurally it is a non-focusable Panel with a MultiStyleLabel that interpolates a component name into a template string. Props: componentName. Used as a stand-in when a showcase has not been implemented.
  • Implementation file: examples/showcase/src/components/tbd-panel.tsx
  • Usage example: Reference the implementation for the pattern.

Boundary

The Boundary component is a container that sizes itself to its children.

  • Name: Boundary
  • When to use: When you need a container that auto-sizes to its children with a visible border. Structurally it is a Rectangle whose dimensions are set dynamically: on mount it triggers a BoundingTracker measurement of its children, then sets the Rectangle width/height to the measured bounds plus configurable padding. The background is a semi-transparent white (#FFFFFF11). Children are arranged inside a vertical LayoutGroup. Props: children, padding (defaults to 5). It measures only once on mount; therefore, children must be static.
  • Implementation file: examples/showcase/src/components/showcases/common/boundary.tsx
  • Usage example: examples/showcase/src/components/showcases/label-showcases/label-showcase-panel.tsx (wraps Label examples to visualize bounding areas)

PropertyChooserDialog

The PropertyChooserDialog component is a data-driven dialog for selecting property values.

  • Name: PropertyChooserDialog
  • When to use: When you need a data-driven dialog for selecting values from a set of named properties. Structurally it is a StandardDialog that renders a list of StdDlgActionCardItem entries from an IPropertyDef[] array: boolean properties render as toggleable checkboxes, non-boolean properties show a "more info" icon and drill down to PropertyValueDialog (child dialog navigation). Returns the edited property set via DialogCloseParams on Apply. Driven entirely by data; no hardcoded fields. Used for runtime component property editing in showcase scenes.
  • Implementation file: examples/showcase/src/components/property-chooser/property-chooser-dialog.tsx
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx (opens via Options key to configure PosterGrid props)

PropertyValueDialog

The PropertyValueDialog component is a single-select radio-button list dialog.

  • Name: PropertyValueDialog
  • When to use: When you need a single-select radio-button list dialog for choosing one value from a set of options. Structurally it is a StandardDialog with StdDlgItemGroup containing StdDlgActionCardItem entries with radiobutton icons. Receives IPropertyValueData (property name, label, options, selected index) and returns the selected index on close. Designed as a child dialog opened from PropertyChooserDialog, but the pattern is reusable for any single-select picker.
  • Implementation file: examples/showcase/src/components/property-chooser/property-value-dialog.tsx
  • Usage example: examples/showcase/src/components/property-chooser/property-chooser-dialog.tsx (opens via openChildDialog)

ItemSelectedDialog

The ItemSelectedDialog component is a one-message, one-button dialog.

  • Name: ItemSelectedDialog
  • When to use: When you need a one-message, one-button dialog. Structurally it is a StandardMessageDialog that receives a message string via IItemSelectedData and renders it with a single "OK" button. Follows the standard dialog close lifecycle. A generic notification/confirmation dialog; pass any message string. Used across list and grid showcases on item selection.
  • Implementation file: examples/showcase/src/components/showcases/list-and-grid-showcase/item-selected-dialog.tsx
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx (opened on OK key press in PosterGrid)

DialogPalette

The DialogPalette component provides a predefined color palette for dialog theming.

  • Name: DialogPalette
  • When to use: When you need a pre-defined color palette for dialog theming. Structurally it is a thin wrapper that renders <rsgPalette colors={dialogPaletteColors} />. The dialogPaletteColors object defines color keys: dialogBackgroundColor, dialogItemColor, dialogTextColor, dialogFocusColor, dialogFocusItemColor, dialogSecondaryTextColor, dialogSecondaryItemColor, dialogFootprintColor. You can pass it as the palette prop on any StandardDialog or variant.
  • Implementation file: examples/showcase/src/components/showcases/dialog-showcases/dialog-palette.tsx
  • Usage example: examples/showcase/src/components/showcases/dialog-showcases/simple-dialog.tsx (passed as palette={<DialogPalette />})

4. Showcase utilities and data

These utilities and data helpers support the showcases.

Showcase-utils (scene helper functions)

These functions support interactive scene showcases.

  • Name: openPropertyChooser, focusLabelText, makeCodeText, makeOptionsKeyHandler, makeOptionsUnhandledKey, HELP_STYLES
  • When to use: Collection of reusable functions for interactive scene showcases:
    • openPropertyChooser(setDialog, title, config, propsState, setPropsState, defaultProps): opens the PropertyChooserDialog, applies results to a signal on close. Handles the full dialog lifecycle.
    • focusLabelText(index, itemText): returns a formatted string like "Focused: #3 - Drama" or "Focused: (none)". Generic index+label formatter.
    • makeCodeText(componentName, id, config, propsState, extraLines?): returns a reactive accessor () => string that generates a JSX-like snippet with current property values. Any component, any props.
    • makeOptionsKeyHandler(onOptionsKey): legacy EventHandlerKey callback for the Options (*) key (you can use makeOptionsUnhandledKey with BackSceneWrapper instead).
    • makeOptionsUnhandledKey(onOptionsKey): returns an onPress handler for BackSceneWrapper / FocusBoundary onUnhandledKey.options.
    • HELP_STYLES: DrawingStyle map with a key tag (bold yellow) for highlighting remote-key names in help text.
  • Implementation file: examples/showcase/src/components/showcases/list-and-grid-showcase/showcase-utils.ts
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx (uses all five exports)

Property chooser types

These types define the property configuration for the property chooser.

  • Name: IPropertyConfig, IPropertyDef, IPropertyOption, PropertyValue, IPropertyChooserData
  • When to use: When defining the property configuration for a showcase that uses the PropertyChooserDialog. IPropertyConfig defines available options for each property. IPropertyDef adds the current selection.
  • Implementation file: examples/showcase/src/components/property-chooser/property-chooser-types.ts
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx (POSTER_GRID_PROPERTY_CONFIG array)

Property chooser utils

These helpers connect the property chooser to scene showcases.

  • Name: applyPropertiesFromDialog, buildPropertiesFromConfig, formatPropertiesAsText, getPropertyValueText, propertyValuesEqual
  • When to use: When integrating the PropertyChooserDialog with a scene showcase. buildPropertiesFromConfig converts config + current state into dialog data. applyPropertiesFromDialog merges dialog results back. formatPropertiesAsText generates the code-panel text.
  • Implementation file: examples/showcase/src/components/property-chooser/property-chooser-utils.ts
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/showcase-utils.ts (used by openPropertyChooser and makeCodeText)

Picsum image utils

The getImage function builds a remote image URL at a specific pixel size.

  • Name: getImage
  • When to use: When you need a remote image URL at a specific pixel size. getImage(width, height, seed) returns an S3-hosted JPEG URL. The seed parameter (0-based) selects different images. You can use it whenever a Poster, grid item, or any image-bearing component needs a remote image source at exact dimensions.
  • Implementation file: examples/showcase/src/components/showcases/showcase-utils/picsum-utils.ts
  • Usage example: examples/showcase/src/components/showcases/poster-showcase/poster-scene-showcase.tsx (poster images at various sizes)
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx (grid item images with reactive sizing)

Video playlist

The getVideoPlaylist function returns a list of video items.

  • Name: getVideoPlaylist, IPlaylistItem
  • When to use: When you need an array of { url, title } objects for video playback. getVideoPlaylist() returns a static list loaded from a JSON file (MP4 URLs). IPlaylistItem is the shared type. You can use it with the Video component's contentIsPlaylist mode or any component that needs a media item list.
  • Implementation file: examples/showcase/src/components/showcases/showcase-utils/video-playlist.ts
  • Data file: examples/showcase/src/components/showcases/showcase-utils/video-playlist.json
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/time-grid-video-preview.tsx

Audio playlist

The getAudioPlaylist function returns a list of audio items.

  • Name: getAudioPlaylist
  • When to use: When you need an array of { url, title } objects for audio playback. getAudioPlaylist() returns a static list loaded from a JSON file (MP3 URLs). Uses the same IPlaylistItem type as the video playlist.
  • Implementation file: examples/showcase/src/components/showcases/showcase-utils/audio-playlist.ts
  • Data file: examples/showcase/src/components/showcases/showcase-utils/audio-playlist.json
  • Usage example: examples/showcase/src/components/showcases/audio-showcase/audio-scene-showcase.tsx

5. Drawing styles and theming

These style maps and palettes define text and dialog theming.

DRAWING_STYLES / RICH_DRAWING_STYLES

These maps define reusable text styles for MultiStyleLabel.

  • Name: DRAWING_STYLES, RICH_DRAWING_STYLES, OK_MESSAGE_STYLES
  • When to use: When you need pre-defined DrawingStyle maps for MultiStyleLabel. These are reusable tag-to-style dictionaries:
    • DRAWING_STYLES: title is SystemFont.MediumBold, white.
    • RICH_DRAWING_STYLES: extends DRAWING_STYLES with h3 (large bold), h4 (medium bold), b (small bold), code (small bold, light blue #AAD4FF).
    • OK_MESSAGE_STYLES: ok is SystemFont.MediumBold, yellow.
      Pass any of these (or your own { [tag]: DrawingStyle } map) as the drawingStyles prop on MultiStyleLabel or InfoPanel.
  • Implementation file: examples/showcase/src/components/drawing-styles.ts
  • Re-export file: examples/showcase/src/components/info-panel/drawing-styles.ts
  • Usage example: examples/showcase/src/components/info-panel/info-panel.tsx (default drawingStyles for body text)

Dialog palette colors

The dialogPaletteColors object and the DialogPalette component define the shared dialog color scheme.

  • Name: dialogPaletteColors, DialogPalette
  • When to use: When you need the shared color scheme for RsgPalette-based dialog theming. dialogPaletteColors is a plain object with eight color keys (background, item, text, focus, focus-item, secondary-text, secondary-item, footprint). DialogPalette is a component that renders <rsgPalette colors={dialogPaletteColors} />. Either export the object directly for custom palette composition, or use the component as palette={<DialogPalette />}.
  • Implementation file: examples/showcase/src/components/showcases/dialog-showcases/dialog-palette.tsx
  • Usage example: examples/showcase/src/components/showcases/dialog-showcases/simple-dialog.tsx

HELP_STYLES

The HELP_STYLES map highlights remote-key names in help text.

  • Name: HELP_STYLES
  • When to use: When you need a DrawingStyle map that highlights a <key> tag in bold yellow. A single-tag style dictionary: { key: { fontUri: SystemFont.SmallBold, color: "#FFFF00FF" } }. You can pass it as drawingStyles to any MultiStyleLabel where you want <key>Options (*)</key> to render highlighted.
  • Implementation file: examples/showcase/src/components/showcases/list-and-grid-showcase/showcase-utils.ts
  • Usage example: Various scene showcases that display help text with remote-key name highlights.

6. Architectural patterns

These patterns are not showcase-specific. Any RSG 2.0 SDK app that uses panels, fullscreen views, dialogs, or menu navigation can adopt them directly.

Pattern: fullscreen scene with back navigation

This pattern builds a fullscreen view that the user can leave with the Back key.

  • When to use: When you need a fullscreen view (for example, a settings screen, detail page, player, or visualization) that the user can leave with the Back key. The pattern is: wrap content in BackSceneWrapper, register the view factory in a registry, and navigate to it by ID.
  • Structure:
    1. Create a component wrapped in BackSceneWrapper (with title and optional showBackHint, showOptions).
    2. Register it in a scene registry (main-scene.tsx → SCENES array) with a unique string ID.
    3. Optionally create a preview/info panel using InfoPanel to show before entering the scene.
    4. Trigger navigation from a menu item or any component via setScreen(id).
  • Reference implementation: examples/showcase/src/components/showcases/poster-showcase/poster-scene-showcase.tsx (scene) + examples/showcase/src/components/showcases/poster-showcase/poster-showcase.tsx (info panel)
  • Reference implementation: examples/showcase/src/components/showcases/busy-spinner-showcase/busy-spinner-scene-showcase.tsx (scene with onUnhandledKey)

Pattern: FocusBoundary (app-level virtual focus)

  • When to use: When routing remote keys through TypeScript instead of distributed KeyHandler / FocusableGroup wrappers. This showcase is the reference implementation of that pattern.
  • Structure:
    1. Anchor node extends FocusBoundaryBase with keyEvent, focusActive, handledKeys, focusPath fields.
    2. Single RootFocusBoundary at app root with initialFocus={ACTIVE_REGION_REF}.
    3. Each active region (menu or fullscreen scene) mounts a nested FocusBoundary with focusId={ACTIVE_REGION_REF} and RegionShellFocusable for SceneGraph-native children.
    4. Scene keys on BackSceneWrapper via onUnhandledKey; irregular grids use inner FocusBoundary + navigationMap + useFocusable.
    5. Do not span FocusBoundary across PanelSet to ListPanel slides; keep panel menus on SceneGraph-native focus (jumpTo, slidingBack, onFocusedChild).
  • Reference implementation: examples/showcase/src/components/showcase-app.tsx
  • Reference implementation: examples/focus-boundary/ (API examples)
  • Docs: documentation/guides/focus-management/focus-boundary.md

Pattern: panel-based content view

This pattern shows content in a side panel instead of a fullscreen view.

  • When to use: When content fits within a side panel and does not need to take over the full screen (for example, a detail view, a settings form, a text description, a component preview). Panels slide in from the right inside a PanelSet and can chain to deeper panels.
  • Structure:
    1. Create a component using <panel panelSize="medium" focusable={false} hasNextPanel={false}> with LayoutGroup for content arrangement.
    2. Wire it into a menu as a getNextPanel factory on a ListMenuPanel or SceneDialogMenu item.
  • Reference implementation: examples/showcase/src/components/showcases/label-showcases/label-showcase-panel.tsx (panel using Boundary for visual grouping)
  • Reference implementation: examples/showcase/src/components/showcases/group-showcase.tsx (panel with animation)

Pattern: hierarchical menu navigation

This pattern builds a multi-level categorized menu.

  • When to use: When you need a multi-level categorized menu (for example, Settings → Audio → Equalizer; Browse → Genre → SubGenre). Two variants:
    1. SceneDialogMenu: items can open fullscreen scenes (sceneDialogId), open modal dialogs (isDialog: true), or drill into sub-panels (getNextPanel). You can use it when items trigger heterogeneous navigation targets.
    2. ListMenuPanel: items drill into child panels only (getNextPanel). You can use it for pure panel-to-panel navigation.
      Both support slidingBack for back-navigation animation and focus restoration across depth levels.
  • Reference implementation (SceneDialogMenu): examples/showcase/src/components/showcases/dialog-showcases/index.tsx
  • Reference implementation (ListMenuPanel): examples/showcase/src/components/showcases/label-showcases/index.tsx
  • Reference implementation (ListMenuPanel): examples/showcase/src/components/showcases/group-submenu.tsx

Pattern: options key opens the property chooser (runtime config)

This pattern lets users change properties at runtime with the Options key.

  • When to use: When any screen should let users change settings or component properties at runtime via the Options (*) remote key. Applicable to settings screens, customization flows, or any view with configurable parameters. It is not limited to showcases.
  • Structure:
    1. Define an IPropertyConfig[] array describing each configurable property and its options.
    2. Hold a createSignal<Record<string, unknown>> for current property values.
    3. Pass onUnhandledKey={{ options: makeOptionsUnhandledKey(onOptionsKey) }} on BackSceneWrapper (or a nested FocusBoundary for irregular grids).
    4. Call openPropertyChooser(setDialog, title, config, propsState, setPropsState, defaultProps) in the key handler.
    5. Spread {...propsState()} onto the target component to apply changes reactively.
    6. Optionally use makeCodeText(...) to display current values in a CodePanel.
    7. Pass showOptions={true} and optionsText to BackSceneWrapper to show the hint in the Overhang.
  • Reference implementation: examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx

Pattern: image resolution imports

This pattern imports images that have FHD and HD variants.

  • When to use: When importing images that have FHD and HD variants. The SDK's build system resolves * glob patterns in import paths to the correct resolution file at build time. You can use it in any app, not just showcases.
  • Syntax: import { uri as myImage } from "./images/my-image-*.webp";
  • Reference implementation: examples/showcase/src/components/scene-wrapper.tsx (import { uri as logo } from "./images/sc-logo-*.webp")
  • Reference implementation: examples/showcase/src/components/showcases/busy-spinner-showcase/busy-spinner-scene-showcase.tsx (import { uri as busySpinnerImage } from "./images/busyspinner-*.webp")

7. Dialog patterns

These patterns cover building and registering dialogs.

Pattern: composable StandardDialog

This pattern composes a modal dialog from title, content, and button areas.

Pattern: StandardMessageDialog (quick message)

This pattern shows a message dialog without a custom content layout.

  • When to use: When you need a dialog with a title, one or more message strings, and buttons, without a custom content layout. Covers confirmations, alerts, and notifications. You can use StandardMessageDialog instead of composing areas manually.
  • Reference implementation: examples/showcase/src/components/showcases/list-and-grid-showcase/item-selected-dialog.tsx
  • Reference implementation: examples/showcase/src/components/showcases/dialog-showcases/terms-conditions-dialog.tsx

Pattern: dialog with child navigation (stacking)

This pattern opens a sub-dialog from a dialog and returns results to the parent.

  • When to use: When a dialog needs to open a sub-dialog and return to the parent with results (for example, Settings, then a sub-category picker, then back to Settings with the selection). The DialogContext stack manages backup/restore of parent data. You can use pendingChild and openChildDialog to push, and getChildCloseParams to process the child's return data.
  • Reference implementation: examples/showcase/src/components/showcases/dialog-showcases/app-settings/app-settings-dialog.tsx
  • Reference implementation: examples/showcase/src/components/property-chooser/property-chooser-dialog.tsx

Pattern: dialog close lifecycle

This pattern defines how a dialog closes.

  • When to use: Every StandardDialog (or variant) must follow this lifecycle. You must guard against duplicate onWasClosed calls with a hasBeenClosed flag.
  • Flow:
    1. User presses a button → onButtonSelected(index) fires → batch setCloseDialog(true) + setSelectedButton(index).
    2. StandardDialog begins its close animation.
    3. Animation finishes → onWasClosed fires.
    4. Call contextCloseDialog({ reason, buttonId, ... }) → DialogContext clears the dialog.
  • Reference implementation: examples/showcase/src/components/showcases/dialog-showcases/simple-dialog.tsx (fully documented lifecycle)

Pattern: registering a new dialog

This pattern adds a new dialog type to an app.

  • When to use: When adding a new dialog type to any app that uses DialogContext.
  • Steps:
    1. Create the dialog component following the close lifecycle pattern.
    2. Register it in the dialog registry (in this app: main-scene.tsx → DIALOGS array) with a unique string ID.
    3. Open it from anywhere via setDialog(id, onCloseCallback, optionalData).
  • Reference implementation: examples/showcase/src/components/main-scene.tsx (DIALOGS array)

8. List and grid scene patterns

These patterns cover list and grid scenes.

Pattern: fullscreen list/grid view

This pattern builds a fullscreen view around a list or grid component.

  • When to use: When building any fullscreen view centered on a list or grid component, such as media browsers, channel guides, settings lists, and category grids. The pattern combines a BackSceneWrapper, a ContentNode data tree, focus tracking, item selection handling, and optional runtime property editing.
  • Structure:
    1. Wrap in BackSceneWrapper with showOptions={true} if property editing is needed.
    2. Build a ContentNode tree for the list/grid content (often reactive via createMemo).
    3. Track the focused item with createSignal<number> and display via focusLabelText.
    4. Handle item selection (for example, open a dialog, navigate to a detail view, trigger an action).
    5. Optionally add a CodePanel with makeCodeText to display current property values.
    6. Optionally wire the Options key to openPropertyChooser for runtime configuration.
  • Reference implementation: examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx (complete pattern)

Pattern: registering a new scene

This pattern adds a new fullscreen view to an app.

  • When to use: When adding a new fullscreen view to any app that uses ScreenRegistryContext (or the underlying ScreenControllerContext).
  • Steps:
    1. Create the view component wrapped in BackSceneWrapper.
    2. Register it in the scene registry (in this app: main-scene.tsx → SCENES array) with a unique string ID.
    3. Optionally create a preview/info panel using InfoPanel.
    4. Add a menu item or trigger that calls setScreen(id) to navigate to it.
  • Reference implementation: examples/showcase/src/components/main-scene.tsx (SCENES array) + examples/showcase/src/components/main-menu.tsx (menu items)

9. Media playback patterns

These patterns cover audio and video playback.

Pattern: imperative media playback via refs

This pattern controls media playback through imperative refs.

  • When to use: When controlling Audio, Video, or SoundEffect playback. Instead of binding a reactive control signal to the component's control prop, obtain an imperative ref (AudioRef, VideoRef, or SoundEffectRef) and call its methods directly. This approach avoids timing issues with batched signal updates and makes the control flow explicit.
  • Structure:
    1. Declare a ref variable: let audioRef!: AudioRef (or VideoRef, or SoundEffectRef).
    2. Pass it to the component: <Audio ref={audioRef} ... />.
    3. Start playback in onMount: audioRef.play().
    4. Stop and release resources in onCleanup: audioRef?.stop().
    5. Call ref methods in event handlers for play/pause/stop/skip.
  • The SoundEffectRef object exposes only .play() and .stop(); the Roku SoundEffect node does not support pause, resume, or skip.
  • Reference implementation: examples/showcase/src/components/showcases/audio-showcase/audio-scene-showcase.tsx (AudioRef with play, pause, resume, stop)
  • Reference implementation: examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/fullscreen-video-scene.tsx (VideoRef with play, stop)
  • Reference implementation: examples/showcase/src/components/showcases/sound-effect-showcase/sound-effect-showcase.tsx (SoundEffectRef with play)

Pattern: audio playlist with transport controls & track skipping

This pattern builds an audio player with playlist support.

  • When to use: When building an audio player with playlist support, transport buttons, and track-skip functionality. Demonstrates how to combine AudioRef imperative control with nextContentIndex for explicit track jumps, onState for state tracking, and onContentIndex for active-track highlighting.
  • Structure:
    1. Load a playlist via getAudioPlaylist() and build a ContentNode tree with contentIsPlaylist and loop.
    2. Track the active track index with a createSignal updated by the onContentIndex callback.
    3. To skip: set nextContentIndex to the target index (with modular arithmetic for wraparound), then call audioRef.play(); the play command restarts playback from the index specified by nextContentIndex.
    4. Toggle play/pause via audioRef.pause() and audioRef.resume() (not play, which restarts the track).
    5. Display playback state from the onState callback.
  • Key fields: contentIsPlaylist, loop, nextContentIndex, onState, onContentIndex
  • Reference implementation: examples/showcase/src/components/showcases/audio-showcase/audio-scene-showcase.tsx

Pattern: two-phase media exit (stop then navigate)

This pattern stops media playback before navigating away.

  • When to use: When a media playback scene needs to stop audio or video and then navigate away. Navigating immediately after calling stop() can tear down the scene while media resources are still active. Both the Audio and Video showcases use the same two-phase approach to release resources cleanly.
  • Flow:
    1. User presses Back → set a local exit / shouldExit flag and call ref.stop().
    2. The media node transitions through states and eventually reports "stopped" through onState.
    3. Inside onState, check state === "stopped" and the exit flag → navigate away (for example, setScreen(null) or closeFullscreenVideo()).
  • Why: The media node may pass through intermediate states (buffering, paused) before confirming "stopped". Deferring navigation to the onState callback releases the resources fully before the app navigates.
  • Reference implementation: examples/showcase/src/components/showcases/audio-showcase/audio-scene-showcase.tsx (sets exit flag, waits for "stopped" in onState, calls setScreen(null))
  • Reference implementation: examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/fullscreen-video-scene.tsx (sets shouldExit flag, waits for "stopped" in onState, calls closeFullscreenVideo())

10. Compiled (BRS/XML) components

These compiled components are SceneGraph XML components with BrightScript implementations.

Custom list/grid item components

These components render the items in list and grid components.

  • Name: MarkupGridItem, MarkupListItem, RowListItem, TimeGridChannelItem, ZoomRowListItem
  • When to use: When a list or grid component requires a custom item renderer (MarkupGrid, MarkupList, RowList, TimeGrid, ZoomRowList). These are SceneGraph XML components with BrightScript implementations, compiled from TypeScript source. They define the visual layout of each item in the list/grid.
  • Implementation files: examples/showcase/src/compiled-components/MarkupGridItem.xml, .brs; examples/showcase/src/compiled-components/MarkupListItem.xml, .brs; examples/showcase/src/compiled-components/RowListItem.xml, .brs; examples/showcase/src/compiled-components/TimeGridChannelItem.xml, .brs; examples/showcase/src/compiled-components/ZoomRowListItem.xml, .brs
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/markup-grid/markup-grid-scene-showcase.tsx (references MarkupGridItem)
  • Usage example: examples/showcase/src/components/showcases/list-and-grid-showcase/row-list/row-list-scene-showcase.tsx (references RowListItem)

BaseAppScene

BaseAppScene hosts the TypeScript app.

  • Name: BaseAppScene
  • When to use: This scene is the base SceneGraph XML scene that hosts the TypeScript app. Imported in examples/showcase/src/index.ts. You should modify this scene only when you change the scene bootstrap.
  • Implementation file: examples/showcase/src/compiled-components/BaseAppScene.xml, .brs
  • Usage example: examples/showcase/src/index.ts (imported at top level)

Adding new views: quick reference

The following sections list the steps for adding each kind of view.

Adding a new fullscreen scene

To add a new fullscreen scene, follow these steps:

  1. Create examples/showcase/src/components/showcases/<name>/<name>-scene-showcase.tsx → wrap in BackSceneWrapper.
  2. Optionally create examples/showcase/src/components/showcases/<name>/<name>-info-panel.tsx → use InfoPanel with title, text, and showOkMessage.
  3. Register the scene in examples/showcase/src/components/main-scene.tsx → add ["<scene-id>", () => <YourScene />] to SCENES.
  4. Add to menu in examples/showcase/src/components/main-menu.tsx or a submenu → { id: "...", title: "...", sceneDialogId: "<scene-id>", getNextPanel: () => <YourInfoPanel /> }.
  5. If the scene needs runtime property editing: follow the Options key property chooser pattern.

Adding a new dialog

To add a new dialog, follow these steps:

  1. Create the dialog component in examples/showcase/src/components/showcases/dialog-showcases/<name>-dialog.tsx → follow the Dialog Close Lifecycle pattern.
  2. Optionally create an info panel in examples/showcase/src/components/showcases/dialog-showcases/<name>-panel.tsx → use InfoPanel.
  3. Register in examples/showcase/src/components/main-scene.tsx → add to DIALOGS array.
  4. Add to examples/showcase/src/components/showcases/dialog-showcases/index.tsx → add item with sceneDialogId: "<dialog-id>" and isDialog: true.

Adding a new panel view

To add a new panel view, follow these steps:

  1. Create examples/showcase/src/components/showcases/<name>/<name>-panel.tsx → use <panel panelSize="medium" focusable={false} hasNextPanel={false}>.
  2. Add to a menu's items array with getNextPanel: () => <YourPanel />.

Adding a new submenu (category grouping)

To add a new submenu, follow these steps:

  1. Use SceneDialogMenu if items open scenes/dialogs, or ListMenuPanel if items only open panels.
  2. Wire into the parent menu's getNextPanel factory.
  3. Pass slidingBack prop through for back-navigation animation.

File index: key files at a glance

The following table lists the key files in the app.

FileRole
examples/showcase/src/index.tsApp entry point
examples/showcase/src/components/showcase-app.tsxRoot component + provider tree
examples/showcase/src/components/main-scene.tsxScene & dialog registry
examples/showcase/src/components/menu-scene.tsxHome screen (fallback)
examples/showcase/src/components/main-menu.tsxTop-level menu items
examples/showcase/src/components/scene-wrapper.tsxFullscreen view with Overhang chrome + Back key
examples/showcase/src/components/scene-dialog-menu.tsxList menu with scene/dialog triggers
examples/showcase/src/components/list-menu-panel.tsxList menu with panel drill-down
packages/navigation/src/screen-controller/screen-controller.tsx@roku-sdk/navigation: factory-based screen stack and fullscreen view switching
examples/showcase/src/components/screen-registry/screen-registry.tsxApp-level id-based registry wrapper around @roku-sdk/navigation's ScreenControllerContext
examples/showcase/src/components/showcases/dialog-showcases/dialog-context.tsxDialog state management
examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/fullscreen-video-context.tsxVideo playback state
examples/showcase/src/components/info-panel/info-panel.tsxTitled rich-text panel with overflow scroll
examples/showcase/src/components/code-panel.tsxPoster-backed panel with custom font
examples/showcase/src/components/tbd-panel.tsxStyled message placeholder panel
examples/showcase/src/components/showcases/common/boundary.tsxAuto-sizing measured container
examples/showcase/src/components/property-chooser/property-chooser-dialog.tsxData-driven option picker dialog
examples/showcase/src/components/property-chooser/property-chooser-types.tsProperty config/option types
examples/showcase/src/components/property-chooser/property-chooser-utils.tsProperty apply/build/format helpers
examples/showcase/src/components/showcases/dialog-showcases/dialog-palette.tsxRsgPalette color scheme for dialogs
examples/showcase/src/components/drawing-styles.tsReusable DrawingStyle maps for MultiStyleLabel
examples/showcase/src/components/showcases/list-and-grid-showcase/showcase-utils.tsScene helper functions (property chooser, key handler, code text)
examples/showcase/src/components/showcases/list-and-grid-showcase/item-selected-dialog.tsxSingle-message OK dialog
examples/showcase/src/components/showcases/showcase-utils/picsum-utils.tsRemote image URL builder
examples/showcase/src/components/showcases/showcase-utils/video-playlist.tsVideo playlist data loader
examples/showcase/src/components/showcases/showcase-utils/audio-playlist.tsAudio playlist data loader

Did this page help you?