Reactive Programming

Reactive Programming

SparkAR Studio uses a reactive programming model, a declarative paradigm which is primarily structured around asynchronous data streams and the propagation of change.

What is reactive programming?

The reactive programming model allows you to define relationships between objects and values in such a way that a value bound to a signal is automatically updated when the latter changes.

Consider value A which is bound to signal B. Whenever the value of B changes, the system reacts to this change and updates the value of A automatically without having to reassign the new value of B to A.

A common example of reactive principles in practice are cell expressions within a spreadsheet. When the value of cell A1 depends on the value of cell B2 and B2 is changed, A1 is automatically updated.

Another example would be the common model-view-controller design pattern, in which changes to the underlying model are automatically reflected in the associated view.

Differences between reactive and imperative programming

If you’ve worked with other development tools in the past you may be more familiar with imperative programming. This model differs from reactive programming in that statements are executed in order and values are set only when an expression is evaluated.

Let's take a look at how this works with the expression: x = y + z, where y has a value of 5 and z has a value of 10. With imperative programming the value of x is set when the expression is evaluated, giving x a value of 15.

The value of x will not change unless it is reevaluated, so even if y is given a value of 10 at a later time x will still be equal to 15.

// With imperative programming, y and z are regular values
var z = 10;
var y = 5;
var x = y + z; 

Console.log(x); // Result: 15

// Even if the value of y changes...
y = 10;

// ...the value of x will not change
Console.log(x); // Result: 15

With reactive programming the values of y and z can be treated as signals to which the value of x is bound. Given the same initial values x will be equal to 15.

However, if the value of y becomes 10 at a later time, the value of x is automatically updated because it is bound to y. In this scenario x will automatically be assigned a new value of 20 without an explicit re-evaluation.

// With reactive programming, y and z can be treated as signals
var z = 10;
var y = 5;
var x = y + z; 

Console.log(x); // Result: 15

// If the value of y changes...
y = 10;

// ...the value of x will be automatically updated
Console.log(x); // Result: 20

Why use reactive programming?

As reactive programming is based around the propagation of data through continuous observation, the engine doesn’t have to execute JavaScript code every frame when performing common tasks such as animating content or realigning an object to a detected face.

Consider a scenario in which we want an object’s x position to change based on the rotation of a face in the camera view. Normally we might expect to implement this logic within an update loop, meaning our JavaScript would run every frame in order to update the object’s position:

// Called every frame, regardless of whether the value of rotation.y has changed or not
function Update(){
    myObject.x = face.rotation.y.currentValue;

With a reactive model the updating of the value happens in native code rather than JavaScript, reducing the impact on application performance.

// Here we only need to bind the y rotation to the x position once
// The reactive model will automatically update the value of x when y changes, avoiding unnecessary calls
myObject.x = face.rotation.y;

The reactive model’s compatibility with visual programming also means that the frequency with which calls are made to the scripting engine is reduced. Both this and the previous points result in performance improvements for your effects.

Additionally, as the reactive model is designed to be non-blocking, other data streams can be disseminated asynchronously without issue.

How does this relate to development in Spark AR Studio?

Using reactive programming in Spark means changing the way you think about the flow of data during the effect's runtime.

Primarily this means that you are able to treat values as signals, which are special objects that contain a value that changes over time. By binding these signals to a variable or an object’s properties you create a reactive system.

Let's take a look at the following example which binds a signal from a source object - the user’s face, to a target object - a plane.

// Load in the required modules
const Scene = require('Scene');
const FaceTracking = require('FaceTracking');
// Enables async/await in JS [part 1]
(async function() {

    // Locate the plane we've added to the Scene panel
    const plane = await Scene.root.findFirst('plane0');
    // Bind the user's face rotation in the Y-axis to the X-position of our plane
    plane.transform.x = FaceTracking.face(0).cameraTransform.rotationY;
// Enables async/await in JS [part 2]

As the object on the left hand side of the assignment, plane.transform.x, is a reactive object the statement is treated as a binding rather than a simple assignment as it would be with standard JavaScript.

For these bindings to work, the value on the right side of the binding must be a signal such as a ScalarSignal or StringSignal for example, rather than a standard scalar or string value.

This means that rather than programming in an imperative style, using conditional logic to control the flow of data and performing explicit assignments to update values, you're programming in a declarative style where data is automatically propagated.

The SparkAR API provides a Reactive module which exposes methods for working with reactive objects.

Learn more about using and working with signals here.