Building a Prototype

An overview and API reference for building JavaScript prototypes driven by a Sketch.systems model.


It can be difficult to understand and communicate a design with just an abstract model. Often, it’s helpful make your design concrete by rendering it as an interactive prototype.

Sketch.systems allows you to build prototypes using JavaScript, HTML, and CSS, which lets you make them as simple or as complex as you need.

Tip: Don’t worry if you’re not a programmer. If you run into some code you don’t understand, try playing with it in sketch to figure it out, or ask a friend for help!

Rendering

Prototypes are defined as a single render function that maps the current system model (a JavaScript object) to a React.js component. Sketch.systems will call this render function after every transition.

Let’s consider the traffic light from the five minute introduction. One of the simplest custom prototypes we could make is to have the render function build a single HTML <span> element with text indicating the current state:

Note: The $ is not jQuery, nor is it a secret call to document.createElement. Instead, it’s a wrapper around React.createElement. This wrapper is just a shorthand that saves typing and makes attributes optional. (If the second argument is an object, it will be interpreted as attributes; otherwise it will be interpreted as an element child.)

Of course, this “prototype” doesn’t tell us anything more than the automatically generated diagram. How are the lights arranged? Can you see the colors of the unilluminated lights, or just the active one?

Let’s answer those questions with a more detailed prototype:

In this prototype there’s a light helper function that returns a <div> representing a single traffic light bulb. This element has inline style attributes: 20px by 20px width and height, with a background color of the light color (if illuminated) or black (if not illuminated).

The render function calls this light helper function three times (once for each light color), and encloses all three of the resulting “bulbs” in a single <div>, resulting in a full traffic light.

Try editing this prototype to change the aesthetics of the light:

  • Build a horizontal-style traffic light by setting display: inline-block on the individual bulbs. That is, Change line 3 to read var attrs = {display: 'inline-block', width: '20px', height: '20px'};. You could also use your mad flexbox skillz on the parent <div>.

  • Make the bulbs circular by adding borderRadius: '10px' to this attribute map.

  • Retain the color on unilluminated bulbs by keeping backgroundColor constant and instead changing opacity. That is, change lines 6 and 8 to read attrs.opacity = 1; and attrs.opacity = 0.2, and add attrs.backgroundColor = color; after the if statement.

If you want to save your experiments or share them with others, you can fork this sketch instead of editing the sketch on this page.

Interaction

As exciting as our traffic light prototype is, it’s still missing a key feature: interactivity. The only way to emit new events and see how the design responds is to click around in the diagram.

Let’s remedy that by adding interaction directly to our prototype:

Here the only change is that we’ve added a <button> with an onClick attribute that calls model.emit("tick"). When this button is clicked, a tick event will be emitted, which (based on our specification) causes the illuminated light to change.

Of course, real traffic lights don’t allow their “users” to emit events — the tick event would be emitted by an internal timer.

This raises an crucial point: For many systems, not every event will correspond to a user interface control (button, key, gesture, etc.).

Sure, some events correspond to user actions, but a system may have many other events that have nothing to do with users: Events that indicate whether data were successfully loaded from a server, that a time interval has elapsed, that a given password is invalid, etc.

Within a sketch, user-facing events should be triggered via iteractions with the prototype, and non-user events should only be triggered by clicking on the diagram.

For more on this topic, see designing behavior.

Now you know the basics of prototyping with Sketch.systems. The best way to solidify your understanding is to build your own prototypes — you can start from scratch, but you can also fork and edit one of these examples:

If you’re using Figma, you can also embed Figma frames directly so that your prototype always reflects your latest drawings.


Reference / Programmer talk

Your prototype’s render function will be invoked after every transition with the resulting model, an object with the following keys:

  • states: an object whose keys are state names and values are states
  • active_states: an array of the active leaf states (there will always be at least one element in the array, since a statechart always has at least one active state)
  • root: the implicit root state of the model
  • emit: a function that can be invoked with an event (a string) to step the model forward

States are objects with the following keys:

  • parent: the parent state (except for the root state, when this field is null)
  • children: an array of children states (if there are no children, this key will not exist)
  • is_active: a boolean indicating whether this state is active (note that this will be true for ancestors of an active leaf)

The $ React helper is defined by:

const $ = function(){
  [a, b, ...rest] = arguments;
  if(('object' === typeof b) && !(React.isValidElement(b))){
    return React.createElement.apply(null, arguments);
  }else{
    return React.createElement.apply(null, [a, {}, b].concat(rest));
  }
};

In addition to this helper, you can also define React components with JSX. However, due to the size of Babel this functionality is disabled on the tutorial pages and available only in the the playground.