BrightScript style guide

Recommended practices for organizing, documenting, and formatting BrightScript and SceneGraph code

Consistent code and meaningful comments make an app easier to maintain, review, and hand off. This guide describes the practices Roku recommends for the project structure, documentation, naming, and formatting of BrightScript and SceneGraph (RSG) apps. You can adopt the guide as a whole or use it as a starting point for your own team's conventions.

Comments

Use the comment syntax that belongs to each file type:

  • In .brs files, begin comments with an apostrophe (') rather than REM.
  • In manifest files, begin comments with a pound sign (#).
  • In .xml files, use the standard XML comment notation (<!-- -->).

Project structure

A SceneGraph app has a manifest file and three main directories: source, components, and images. See Developing SceneGraph apps for the full description of the app directory structure.

MyApp/
  manifest
  source/
    main.brs
  components/
    screens/
      AboutScreen/
        AboutScreen.xml
        AboutScreen.brs
  images/
    app-poster_fhd.png
    splash-screen_fhd.jpg

Organizing component subdirectories

If your app has many related components with related BrightScript files, create subdirectories in the components directory to group them by purpose. In the preceding example:

  • All screen components are under the screens subdirectory.
  • The screens subdirectory has an AboutScreen subdirectory with all the files for the About screen.
  • Use the same approach for the other main directories: organize their files into logical subdirectories.

The manifest file

Group related entries in the manifest file, add a header comment, and comment each block with relevant information. The following example shows a well-documented manifest file. See Manifest file for all supported attributes.

# Copyright (c) <year> <company>. All rights reserved.
# Roku app manifest file

# App details
title=Hello World
major_version=1
minor_version=0
build_version=00001

# App assets
# Main menu icons / app poster artwork
# Image sizes are FHD: 540x405px | HD: 290x218px | SD: 214x144px
mm_icon_focus_fhd=pkg:/images/app-poster_fhd.png
mm_icon_focus_hd=pkg:/images/app-poster_hd.png
mm_icon_focus_sd=pkg:/images/app-poster_sd.png

# Splash screen and loading screen artwork
# Image sizes are FHD: 1920x1080px | HD: 1280x720px | SD: 720x480px
splash_screen_fhd=pkg:/images/splash-screen_fhd.jpg
splash_screen_hd=pkg:/images/splash-screen_hd.jpg
splash_screen_sd=pkg:/images/splash-screen_sd.jpg

splash_color=#000000
splash_min_time=1

Grouping related entries lets you see which attributes belong together at a glance. In the example, the app details are in one block, and the poster artwork entries are in another with the image sizes noted.

The source directory

The source directory contains the BrightScript code for the app's main execution thread. In a SceneGraph app, this directory usually contains only main.brs, and the rest of the BrightScript files are in the components directory.

The components directory

  • Put all XML component files and the BrightScript files they use in the components directory.
  • Include a single <component> element in each XML component file.

Linking BrightScript files from components

Link to BrightScript files from XML components instead of embedding the code in a CDATA section. Separating the code from the component markup keeps business logic apart from the view, and many editors and IDEs cannot highlight syntax or support debugging for code inside a CDATA section.

<script type="text/brightscript" uri="pkg:/components/MyComponent.brs" />

The images directory

Put all graphics and other assets that you include in the app package in the images directory. At a minimum, this directory must contain the app selection (main menu icon) and splash screen images.

Code structure

Theming SGDEX apps

If your app uses the Roku SceneGraph Developer Extensions (SGDEX), follow these guidelines for theming:

  • Place the theme logic at or near the beginning of the Show() function.
  • Put theme attributes that apply to all views in the global section of the theme.
  • Put theme attributes that apply to a specific type of view in the section of the theme for that view type.
  • Do not set theme attributes directly on a view instance unless you want the attributes to apply to only that view.

Documenting your code

Apply the practices in this section to each project file.

File headers

Begin each source file (.brs and .xml) with a comment that states the company and copyright information and the general purpose of the file. For a large file, also describe its internal and external context:

  • Any global data that the file initializes or uses, such as fields assigned to the m object.
  • What the file does.
  • The files that depend on it and the files it depends on.
  • Any other helpful information, such as contact information for the developer or warnings about known issues.

Function headers

Add a comment above each complicated function that describes what it does, the parameters it takes, and its return value. There is no required format for these comments. A common approach is to use @param and @return tags.

' Adds two integers and returns the result.
' @param a: the first integer
' @param b: the second integer
' @return The sum of a and b as an integer
function Add(a as Integer, b as Integer) as Integer
  return a + b
end function

Avoid functions with no comment, no parameter types, and no return type:

function add3(a, b)
  return a + b
end function

Use sub instead of function when a function has no return value:

' Do
sub SomeFunction()
  ? "something"
end sub
' Do not
function SomeFunction()
  ? "something"
end function

Inline comments

Add short comments that help readers follow the flow of the code. Other people will read your code, and details that seem obvious to you may not be obvious to them. As a general rule, write a comment for each block of logic, such as a function, if statement, or loop.

Grouping related entries

Group related fields and assets together and name them with a common prefix. In the manifest example, the app details are in one block, and the artwork entries share the app-poster prefix. If you have several files for the same asset, give them a common prefix and vary only the resolution, for example app-poster_fhd.png, app-poster_hd.png, and app-poster_sd.png.

Supporting multiple API environments

If your app connects to the same API in several environments (for example, development, staging, and production), make it possible to switch environments by changing one variable. Put the variable in a prominent place and document it.

' apiEnvironment controls which API the app uses
' Possible values: "DEV", "STAGE", "PROD"
apiEnvironment = "STAGE"

Naming and formatting

Line length

Keep each line of code under 80 characters whenever possible. Shorter lines make it easier to open several files side by side, for example when you split a window or compare two files.

Indentation

  • Use 2 or 4 spaces for each level of indentation.
  • Do not use tabs.

Whitespace

  • Do not leave whitespace at the end of a line.
  • Put one blank line between functions.
  • Do not use two consecutive blank lines.
  • Do not put blank lines after a function signature or before its closing line.
  • Put one space after each comma in a parameter list.
  • End each file with a single blank line.
  • Do not print blank lines to the console.

Capitalization

  • Write keywords such as if, else, for, next, sub, function, end, and as in lowercase.
  • Begin function names with a capital letter.
  • Begin variable names with a lowercase letter.

Meaningful names

Choose variable and function names that describe what they are. Name functions with verbs or phrases that state the action they perform. In SceneGraph XML, name fields with nouns, not verbs.

<!-- Do -->
<field id="videoPlayer" type="node" onChange="SetVideoPlayer" />

<!-- Do not -->
<field id="InitVideoPlayer" type="node" onChange="OnMainContent" />

Descriptive names make code easier to read out of context:

' Do
' Returns the time, in minutes, from the hours and minutes passed in.
' @param hours: the current hour
' @param minutes: the current minute
' @return The time in total minutes as an integer
function GetTotalMinutes(hours as Integer, minutes as Integer) as Integer
  return hours * 60 + minutes
end function
' Do not
function Mn(ho, mn)
  rn = ho * 60 + mn
  return rn
end function

The second function is much harder to understand without more context.

Grouping code in blocks

Group logically related lines together and separate the groups with a blank line, so readers can see how lines relate.

' Do: statements are grouped by property
m.background.width = m.top.width
m.oldBackground.width = m.top.width
m.shade.width = m.top.width
m.backgroundColor.width = m.top.width

m.background.height = m.top.height
m.oldBackground.height = m.top.height
m.shade.height = m.top.height
m.backgroundColor.height = m.top.height
' Do not: related statements are scattered
m.background.width = m.top.width
m.oldBackground.width = m.top.width
m.oldBackground.height = m.top.height
m.background.height = m.top.height
m.shade.height = m.top.height
m.shade.width = m.top.width
m.backgroundColor.width = m.top.width
m.backgroundColor.height = m.top.height

Debug statements

Remove debug statements from production code. Print statements can affect performance. If you need them during development, wrap them in a debug flag so you can turn all debug output on or off in one place.

if m.debug then ? "DEBUG: user signed in"

Syntax

Printing and strings

  • Use ? instead of print.
  • Put one space after ? and before the opening quotation mark.
  • Use + to concatenate strings.

Assignments

Put one space on each side of the equal sign.

myVar = newValue   ' Do
myVar=newValue     ' Do not

Arrays

  • Declare an ordered array on one line, unless it represents a matrix or the declaration exceeds 80 characters.
  • Put one space after each comma, and no space between the values and the brackets.
myArray = [1, 2, 3]

Associative arrays

  • Declare associative arrays on multiple lines, with each attribute on its own line, including when you define them inline.
  • Do not put a blank line between the opening brace and the first attribute.
  • Do not put a space between an attribute name and the colon, and put at least one space between the colon and the value.
  • You can add extra spaces after the colon so that values line up vertically.
myAA = {
  key1: value1
  key2: value2
}

If statements

When an entire if statement is less than 80 characters, put it on a single line.

if m.debug then ? debugStr

SceneGraph XML files

  • Define an element on a single line only if the definition is less than 80 characters.
  • Break a longer definition into multiple lines with exactly one attribute per line, indented from the opening tag. Put the closing tag on its own line, at the same indentation as the opening tag.
  • Indent child elements from their parent.
  • Put one blank line before each new sibling element.
  • Do not put a blank line between a parent's opening tag and its first child element.
  • On a single-line element, put one space before the closing />.
  • Do not put spaces around the equal sign in an attribute.
<!-- Do -->
<myParent>
  <myElement id="myID" type="int" />

  <myLongElement
    id="myID"
    type="int"
    value="42"
    attribute1="value"
    attribute2="value"
  />
</myParent>
<!-- Do not -->
<myParent>
<myElement id="myID" type = "int"/>
<myLongElement id="myID" type="int" value="42" attribute1="value" attribute2="value"/>
</myParent>

Related documentation


Did this page help you?