Create Your First Rig
The best way to discover what Slipway can do is by reading through the Basics section section of the documentation, which comes next.
However to quickly get a feel for Slipway follow the walkthrough below to create a Component and a Rig, and run them using a Slipway Server in just a few short files.
First, ensure you have installed Slipway.
Quick Start
We're going to create a Component, and then run the Component in a Rig to render a dashboard. Finally we'll host the Rig in a Slipway server so that the Rig can be run on demand over a network.
The terminal commands given below should work on Linux, MacOS and under WSL in Windows.
Create a new folder for this example:
mkdir slipway_example
cd
into the folder:
cd slipway_example
Create a folder for your Javascript Component:
The convention is for a component to live in a folder named components/{publisher}.{name}
.
For this example we'll use the publisher name demo
and the Component name hello_world
.
mkdir -p components/demo.hello_world
Create a folder for your Rig:
The convention is for Rigs to live in a folder named rigs
.
mkdir rigs
Create the Component:
We're going to create a Javascript Component which takes some text as an input, and outputs a renderable layout in JSON which contains that text.
This will require creating two files: slipway_component.json
and run.js
.
The Component files should all created in the components/demo.hello_world
folder.
Create a file called slipway_component.json
containing the following JSON:
{
"publisher": "demo",
"name": "hello_world",
"version": "1.0.0",
"input": {
"properties": {
"text": { "type": "string" }
}
},
"output": {}
}
The slipway_component.json
file contains the Component metadata, including defining the valid inputs and outputs
to the component.
In this case we've defined that the component input contains a property called text
of type string
,
and the Component can output any JSON.
Create a file called run.js
containing the following Javascript:
export function run(input) {
const timezone = process.env.TZ;
const now = Temporal.Now.plainDateTimeISO(timezone);
const time = `${padded(now.hour)}:${padded(now.minute)}:${padded(now.second)}`;
let outputText = `${input.text}\n${time}`;
return {
"type": "AdaptiveCard",
"verticalContentAlignment": "center",
"body": [
{
"type": "TextBlock",
"horizontalAlignment": "center",
"text": outputText
}
]
};
}
function padded(num) {
return num.toString().padStart(2, '0');
}
The run.js
file contains the Javascript that will be executed for the Component.
In this case it returns a simple Adaptive Cards definition
that will render the text supplied in the input centered horizontally and vertically,
along with the current time.
Slipway validates the input to your Component before calling the run
function,
using the schema defined in slipway_component.json
.
Schemas can be defined using either JsonTypeDef or JSON Schema.
We will use an Adaptive Cards renderer to render our text in this example, however Slipway itself is renderer agnostic and can use any rendering Component. For example we could instead supply JSX to a JSX renderer.
Test the Component:
We can quickly test our Component outside of a Rig using the slipway run-component
command.
Run the following in your terminal:
slipway run-component "file:components/demo.hello_world" --input "{ \"text\": \"Hello there\" }"
You should see the expected output in the terminal:
{
"body": [
{
"horizontalAlignment": "center",
"text": "Hello there",
"type": "TextBlock"
}
],
"type": "AdaptiveCard",
"verticalContentAlignment": "center"
}
Create the Rig:
The Rig file below should be created in the rigs
folder.
The Rig file defines how components will be composed together to produce an output.
We will call our Rig hello
by creating a file called hello.json
in the rigs
folder:
{
"rigging": {
"hello_world": {
"component": "demo.hello_world.1.0.0",
"input": {
"text": "Hello World!"
}
},
"output": {
"component": "slipwayhq.render.0.6.1",
"input": {
"card": "$$.hello_world",
"canvas": {
"width": 800,
"height": 480
}
},
"allow": [
{ "permission": "fonts" }
]
}
}
}
This Rig defines the input to the demo.hello_world
Component we just created, specifying that we want to render the
text Hello World!
.
It then feeds the Component's output into the card
property of the slipwayhq.render
Component's input.
The slipwayhq.render
Component understands how to render Adaptive Cards definitions, and outputs
a rendered canvas.
The $$.hello_world
string in the above JSON tells Slipway to substitute at that location the output of the component with handle hello_world
. It is a convenient shorthand for the JsonPath query $.rigging.hello_world.output
. This is discussed in more detail later.
This is how we define how data flows from one Component to another.
In the above Rig you can see that we explicitly give the slipwayhq.render
component permission to load fonts from the host system.
Slipway uses a zero-trust security model for both Rigs and Components.
Run your Rig:
Your file system should now look something like this:
slipway_example
├─ components
│ └─ demo.hello_world
│ └─ run.js
│ └─ slipway_component.json
└─ rigs
└─ hello.json
From the root slipway_example
folder, execute the following command to run your rig:
slipway run --allow-all --registry "file:components/{publisher}.{name}" rigs/hello.json
Let's break this down:
-
slipway run
tells Slipway we want to run a rig. -
--allow-all
indicates we trust the Rig to give any appropriate permissions to Components. It does not indicate we trust the Components. See the permissions section for more information. -
--registry "file:components/{publisher}.{name}"
tells Slipway to treat that relative path as a Component Registry, and search it for any referenced Components. This is where ourhello_world
Component lives. If a Component isn't found there, it will fall back to the default Slipway Component Registry. -
rigs/hello.json
specifies the Rig we want to run.
You should see output similar to the following in the console, followed by a rendering of the final dashboard:
Launching rigs/hello.json
◩ hello_world ┆ 6fde7398 ┆ 23 bytes
└─□ output ┆ ┆
Running "hello_world"...
Component "hello_world" finished running.
■ hello_world ┆ 6fde7398 ➜ 6cfa9a4b ┆ 23 bytes ➜ 152 bytes ┆ 2ms of 3ms
└─◩ output ┆ fa87a452 ┆ 197 bytes
Running "output"...
Component "output" finished running.
No more components to run.
■ hello_world ┆ 6fde7398 ➜ 6cfa9a4b ┆ 23 bytes ➜ 152 bytes ┆ 2ms of 3ms
└─■ output ┆ fa87a452 ➜ 8c13d949 ┆ 197 bytes ➜ 1.95 mb ┆ 7ms of 454ms
If your terminal doesn't support displaying images, you can add a -o results
argument to write the outputs
to a results
folder:
slipway run -o results --allow-all --registry "file:./components/{publisher}.{name}" rigs/hello.json
In this case there will only be one output, results/output.png
, which should look something like this:
Keep in mind that the image rendered in the terminal, while a very useful approximation of the actual image,
will be lower quality (and often a distorted aspect ratio) compared to the image you'd see on your device,
or if you use the -o
argument to write the result to disk. This is just due to the limitations of rendering
images in the terminal.
Hosting Your Rig
Now we have a Rig, it's easy to host it so that it can be served over a network.
First we initialize the configuration files for the built in HTTP server:
slipway serve . init
This will create a slipway_serve.json
file, a Dockerfile
(to make hosting easy) and a number of
additional (empty) folders which are used for configuring features such as Playlists and Devices.
The defaults should be basically fine for this example. There are just a couple of additions we need to make.
First add an API key:
slipway serve . add-api-key --name "example_key"
This will add a hashed API key to the slipway_serve.json
file, and output the unhashed key to the terminal.
Make a note of the unhashed key displayed in the terminal, as we will use it in a moment.
Next edit slipway_serve.json
and update the rig_permissions
as follows:
"rig_permissions": {
"hello": {
"allow": [
{ "permission": "all" }
]
}
}
This equivalent to the --allow-all
argument we used with the slipway run
command earlier.
It tells the Slipway server that we trust the Rig called hello
to give appropriate permissions to any Components
that it uses.
Finally we can run the server:
slipway serve .
A server will start on port 8080. In your browser you can navigate to the following URL to view your rig,
replacing <YOUR_API_KEY>
with the unhashed key displayed in the console when you ran the add-api-key
sub-command above:
http://localhost:8080/rigs/hello?authorization=<YOUR_API_KEY>
The image we saw earlier should appear in your web browser. In your terminal where you ran slipway serve .
you should
be able to see the logs of the Rig being generated. Each time you refresh the browser the dashboard is generated again.
Passing the API key as a query string parameter is not generally recommended for security reasons.
Passing it using the authorization
header is preferred, but not always possible.
See the API Keys documentation for more information.
Automatic Refresh
The above URL rendered our Rig once and returned it. But as we're displaying the time it might be nice to have it refresh automatically.
Stop your Slipway server, if it is still running, with Ctrl+C
in the terminal.
We'll add a playlist using the add-playlist
sub-command,
which saves us creating the file ourselves:
slipway serve . add-playlist --name every_so_often --rig hello
You'll now find a file in your playlists
folder called every_so_often.json
.
Open this file and it will look like this:
{
"schedule": [
{
"refresh": {
"minutes": 5
},
"rig": "hello"
}
]
}
Change "minutes": 5
to "seconds": 10
because we don't have all day.
The file should now look like this:
{
"schedule": [
{
"refresh": {
"seconds": 10
},
"rig": "hello"
}
]
}
Now start your server again:
slipway serve .
But this time navigate to the following URL:
http://localhost:8080/playlists/every_so_often?format=html_embed&authorization=<YOUR_API_KEY>
Note that we're now navigating to /playlists/every_so_often
, and we've added the
format=html_embed
query string parameter which tells the server to return an HTML page
with an embedded image, rather than just returning the image directly.
Now the page will automatically refresh itself every 10 seconds, thanks to the following
in the HTML's <head>
section:
<meta http-equiv="refresh" content="10">
Slipway isn't really intended for rapid refreshing, more for refreshes on the scale of minutes, or perhaps even hours or days. However for the purposes of this tutorial we won't make you wait that long.
At the moment it refreshes 10 seconds after the browser receives its payload, and there may
be some drift over time as each screen takes a moment to render, exaggerated because
the slipwayhq.render
WASM component is being JIT compiled in this tutorial.
But what if we wanted it to refresh precisely every 10th second of each minute?
We can use cron
syntax to specify this:
{
"schedule": [
{
"refresh": {
"cron": "*/10 * * * * *"
},
"rig": "hello"
}
]
}
Save the file and your page should start refreshing roughly every 0th, 10th, 20th, 30th, 40th and 50th second of each minute (give or take a second), and it won't drift.
In the real world you'd use this to schedule refreshes precisely on the hour, or every 15th minute of every hour, etc. This is very useful for knowing when the screen was last generated, and when it will next update.
Playlists can also be used to display different Rigs depending on the time of day, or day of week. And they also work perfectly with TRMNL devices, controlling exactly when the eInk screen should refresh, and what it should display.
What Next?
You've now created a basic Component and a Rig, but neither are super useful, unless you want a slow refreshing eInk clock.
Clicking "Next" below will take you through the Basics section of the documentation, which will show you how to do more interesting things in Slipway, such as creating Rigs and Components which fetch data and plot charts, how to compose multiple components onto a single screen, and how to display get the outputs of Rigs onto your devices.
If you want to use Slipway with TRMNL devices, you might also want to complete the TRMNL Quick Start.