Glowscript

asynchronous programming language

Glowscript is a simple yet powerful asynchronous multithreaded procedural programming language for creating multilayered (superimposed) animations on smart LED strips, such as DotStars and NeoPixels.


Features

  • A single glowscript program can run 256 independent animation threads and drive over 1000 LEDs.

  • LEDs can be grouped and assigned to multiple animation threads to create complex light patterns.

  • Animation z-ordering allows superimposed animations.

  • Timing instructions permit LED color changes as rapidly as every millisecond or as slowly as every month.

  • Color data compression reduces complex animations to a compact footprint.


Syntax


glowImmediate

syntaxglowImmediate: [led1,led2,…] color
actionInstantly sets the color of the specified LEDs.
e.g. 1glowImmediate: [led5] green
e.g. 2glowImmediate: [led1,led2,led7] red

glowRamp

syntaxglowRamp: [led1,led2,…] color1 to color2 in timeDuration
actionInstantly sets color1 on the specified LEDs, then transitions color1 to color2 over the specified time duration.
e.g. 1glowRamp: [led15,led4] green to blue in 100ms
e.g. 2glowRamp: [led19] red to orange in 5s

pause

syntaxpause: duration
actionPause current thread for the specified duration. Time units can be milli-seconds, seconds, minutes, hours, or ticks. Minimum pause duration is 1 millisecond. Maximum pause duration is 1080 hours (45 days). The pause duration must be a multiple of the device:tickIntervalMillisecs parameter value, which is the time interval between animation update cycles.
e.g. 1pause: 5ms
e.g. 2pause: 30s
e.g. 3pause: 20m
e.g. 4pause: 1h
e.g. 5pause: 40t

here

syntaxhere: bookmarkName
actionBookmark a location in the current function.
e.g. 1here: strobeStart

goto

syntaxgoto: bookmarkName
actionJump to a bookmark in the current function.
e.g. 1goto: strobeStart

call

syntaxcall: @targetFunction
actionSynchronously runs the target function (current function pauses until the target function completes). The z-order is 0 and cannot be modified.
e.g. 1call: @redStrobeFunction

repeat

syntaxcall: @targetFunction (repeat=N)
actionSynchronously runs the target function N times (current function pauses until all repetitions of the target function completes). Using the repeat parameter is optional. Minimum repeat value is 1 (same as omitting repeat parameter). Maximum repeat value is 2 billion. Repeat is used in conjuction with the call instruction.
e.g. 1call: @redStrobeFunction (repeat=50)

callAsync

syntaxcallAsync: @targetFunc
actionAsynchronously runs the target function (current function continues immediately after launching the target function). The callAsync instruction can be nested at any level of your code.
e.g. 1callAsync: @blueStrobeFunc

zOrder

syntaxcallAsync: @targetFunc (zOrder=N)
actionAsynchronously runs the target function with a z-order of N (current function continues immediately after launching the target function). When different animation functions act on the same LED(s), the function with the highest z-order controls the LED(s). If threads have the same z-order, then the last-launched thread wins. Z-order values do not need to be consecutive as the compiler uses them as relative values. Using the z-order parameter is optional. Minimum z-order value is 0 (default z-order parameter). Maximum z-order value is 1000. Z-order is used in conjuction with the callAsync instruction.
e.g. 1callAsync: @blueStrobeFunc (zOrder=2)
e.g. 2callAsync: @lightBeamFunc (zOrder=35)

define

syntaxdefine: alias='value'
actionSets a user-friendly alias for the specified string value. This helps with readability and code-maintenance.
e.g. 1define: strobeLeds='[2,3,4,5,9]'
e.g. 2define: purple='(255,0,255,1)'

comments

syntax//
actionAdd a single-line comment.
e.g. 1// this is a comment line


Specifying LEDs
LEDs are specified by their numeric position from the start of the LED strip (i.e. 1,2,3 and so on) in the following format: [1,2,3] or [1-3] or [1,2-3]).

Specifying colors/brightness
A color is specified by its red value (0-255), green value (0-255), blue value (0-255), & brightness value (0-31) in the following format: (redVal, greenVal, blueVal, brightVal).

Case sensitivity
Glowscript is case-insensitive.


Animation Examples

Synchronous Code Example

Synchronous code executes sequentially and each code instruction completes before the next one is executed. This basic code sample uses synchronous code to toggle all LEDs on and off in a continuous loop.


// DEVICE PARAMETERS (modify with care)

 

    // Elektra simulator

    device: name = 'simulator-elektra-20'

    device: type = 'sim'

    device: tickIntervalMillisecs = '50'     // increase to reduce CPU load.

    device: protocolVersion = '1.0'

    device: ledCount = '20'

    device: ramSpaceBytes = '25000'          // set an animation size limit in memory.

    device: romSpaceBytes = '200000'         // set an animation size limit on disk.

 

// DEFINES (modify as needed)

 

    // LED defines:

    define: innerLeds = '[1-4]'    // alias for inner-ring leds.

    define: middleLeds = '[5-12]'

    define: edgeLeds = '[13-20]'

    define: allLeds = '[1-20]'

 

    // Color defines:

    define: red = '(255,0,0,1)'

    define: green = '(0,255,0,1)'

    define: blue = '(0,0,255,1)'

    define: yellow = '(255,255,0,1)'

    define: white = '(250,250,250,1)'

    define: orange = '(255,165,0,1)'

    define: purple = '(255,0,255,1)'

    define: off = '(0,0,0,1)'

 

// CODE

 

// Continuously loops.

// Each loop cycle has a 1.5 second duration.

@start                             // mandatory entry-point function name.

    here: start_tag1               // set bookmark.

    glowImmediate: allLeds yellow  // set all LEDs to yellow.

    pause: 750ms                   // pause for 750 milliseconds.

    glowImmediate: allLeds off     // turn all LEDs off.

    pause: 750ms                   // pause for 750 milliseconds.

    goto: start_tag1               // loop back to bookmark.

 

The DEVICE PARAMETERS section should not normally be modified. The DEFINES section specifies the label allLeds as an alias for all 20 LEDS (to make CODE section instructions more readable). Most defines are unused and can be deleted. Further defines may be added as necessary.

The CODE section contains executable instructions organized in functions. In this example, only a single function exists, which is the mandatory @start function. @start executes its code instructions in a continuous synchronous loop of 1.5 seconds duration. During each loop cycle, all LEDs turn on for 750ms then turn off for 750ms. The final goto instruction ensures that the code continuously loops, otherwise the simulation will terminate after the first animation cycle.

Asynchronous Code Example

Asynchronous code can execute in parallel with other code. A CPU with one core executing multiple threads achieves asynchronous code execution. A CPU with multiple cores each executing a single thread also achieves asynchronous code execution. This asynchronous code sample uses 4 threads: 1 for the @start function, and 1 for each LED ring.


Glowscript:

// DEVICE (modify with care)

 

    // Elektra simulator

    device: name = 'simulator-elektra-20'

    device: type = 'sim'

    device: tickIntervalMillisecs = '50'     // increase to reduce CPU load.

    device: protocolVersion = '1.0'

    device: ledCount = '20'

    device: ramSpaceBytes = '25000'          // set an animation size limit in memory.

    device: romSpaceBytes = '200000'         // set an animation size limit on disk.

 

// DEFINES (modify as needed)

 

    // LED defines:

    define: innerLeds = '[1-4]'    // alias for inner-ring leds.

    define: middleLeds = '[5-12]'

    define: edgeLeds = '[13-20]'

    define: allLeds = '[1-20]'

 

    // Color defines:

    define: red = '(12,0,0,1)'

    define: green = '(0,12,0,1)'

    define: blue = '(0,0,12,1)'

    define: turquoise = '(0,10,10,1)'

    define: yellow = '(10,10,0,1)'

    define: white = '(4,4,4,1)'

    define: orange = '(30,10,0,1)'

    define: purple = '(10,0,10,1)'

    define: off = '(0,0,0,1)'

 

// CODE

 

// Simultaneously launches 3 functions then exits.

@start                             // mandatory entry-point function name.

    callAsync: @strobeInnerRing    // launch function asynchronously.

    callAsync: @pulseMiddleRing     // launch function asynchronously.

    callAsync: @strobeEdgeRing     // launch function asynchronously.

 

// Continuously runs inner-ring light strobe. Each loop cycle has a 1-second duration.

@strobeInnerRing

    here: start_tag                     // set bookmark.

    glowImmediate: innerLeds red        // set led(s) to red.

    call: @flashInnerRing (repeat=5)    // synchronously call function 5 times.

    pause: 500ms                        // pause for 500 milliseconds.

    goto: start_tag                     // loop back to bookmark.

 

// Flashes inner-ring LED(s) once then exits.

@flashInnerRing

    pause: 50ms                    // pause for 50 milliseconds.

    glowImmediate: innerLeds off   // turn led(s) off.

    pause: 50ms

    glowImmediate: innerLeds red   // set led(s) to red.

 

// Pulses middle-ring LED(s) in a continuous loop. Each loop cycle has a 1-second duration.

@pulseMiddleRing

    here: start_tag                          // set bookmark.

    glowRamp: middleLeds off to red in 500ms  // gradually brighten led(s) to red.

    glowRamp: middleLeds red to off in 500ms  // set led(s) to red then fade off.

    goto: start_tag                          // loop back to bookmark.

 

// Continuously runs edge-ring light strobe. Each loop cycle has a 1-second duration.

@strobeEdgeRing

    here: start_tag                     // set bookmark.

    glowImmediate: edgeLeds off         // set led(s) to off.

    pause: 500ms                        // pause for 500 milliseconds.

    call: @flashEdgeRing (repeat=5)     // synchronously call function 5 times.

    goto: start_tag                     // loop back to bookmark.

 

// Flashes edge-ring LED(s) once then exits.

@flashEdgeRing

    pause: 50ms                         // pause for 50 milliseconds.

    glowImmediate: edgeLeds off         // turn led(s) off.

    pause: 50ms                         // pause for 50 milliseconds.

    glowImmediate: edgeLeds red         // set led(s) to red.

 

Code execution begins with the mandatory @start function, which simultaneously launches 3 functions (@strobeInnerRing, @pulseMiddleRing, @strobeEdgeRing) before exiting. The 3 functions execute in parallel as described below:

  • @strobeInnerRing executes in a continuous synchronous loop of 1-second duration. During each loop cycle, all inner ring LEDs strobe on-off rapidly for 500ms (through repeated synchronous calls to the @flashInnerRing function), then are steady on for 500ms.

  • @strobeEdgeRing executes in a continuous synchronous loop of 1-second duration. During each loop cycle, all edge ring LEDs are off for 500ms, then strobe on-off rapidly for 500ms (through repeated synchronous calls to the @flashEdgeRing function).

  • @pulseMiddleRing executes in a continuous synchronous loop of 1-second duration. During each loop cycle, all middle ring LEDs gradually transition from off to red in 500ms, then gradually transition from red to off in 500ms.


See animation samples for further usage examples.