App(
width: 300
height: 300
align: center
Button(
text: "Start"
bold: yes
color: white
size: 16
backgroundColor: green
do: () ->
timer.start()
)
Button(
text: "Stop"
bold: yes
color: white
size: 16
backgroundColor: red
do: () ->
timer.stop()
)
Button(
text: "Reset"
bold: yes
size: 16
do: () ->
text.text = "00:00.0000";
timer.reset()
)
timer = Timer(
freq: 10
do: (_, ms, s, m) ->
if ms.toString().length == 1
millis = "000" + ms
else if ms.toString().length == 2
millis = "00" + ms
else if ms.toString().length == 3
millis = "0" + ms
else
millis = ms
seconds = if s.toString().length == 1 then "0" + s else s;
minutes = if m.toString().length == 1 then "0" + m else m;
text.text = minutes + ":" + seconds + "." + millis;
)
Paragraph(
width: 300
top: 130
align: "center"
text = Text(
text: "00:00.0000"
size: 32
font: sansSerif
)
)
)
The Web is mainly powered by 3 languages: HTML, CSS, and JS. The goal of Slippers is to allow you, dear reader, to get a headstart by mastering only 1 language, and let Slippers do some of the heavy lifting for you.
Slippers is best used with CoffeeScript. CoffeeScript is a delightful programming languages that's flexible and expressive. It almost reads like English! You will need some very basic knowledge about programming to use Slippers (things like: what is a function? what is a variable?). But you do not need to know anything about the Web, or any of the aforementionned languages (although some knowledge about JS will help).
The foundation for any Slippers app is the App element.
Use it as the "frame" for your virtual "painting":
App()
You can give it some instructions (called "parameters") on how it should look. For example, if you want to give it a certain width and height:
App(
width: 300
height: 300
)
Notice there are some spaces in front of those
width and height keywords. This is known
as indentation and is very important. The amount of spaces
isn't important (2 spaces, 3 spaces, 8, whatever), as long as you
remain consistent.
Next, you can "nest" other elements inside your
App "frame". For example, how about a line of text that
says "Hello!":
App(
width: 300
height: 300
Button(
text: "Click me"
do: () ->
alert("Hello!")
)
)
Notice we keep "indenting" the code. This allows the program to understand the relationship between the elements and their parameters (more on that in a moment).
You may also have noticed the do: () -> line. This is
what's called a "callback", and it will get executed everytime the
button is clicked (more on that in a moment). The indented lines
underneath this do: parameter are all part of this
callback.
You can keep a reference to an element by assigning it to a
"variable". You must give it a name, and it can be whatever you
want. Just use an equal sign (=) to "assign" your
element to your variable. You can then use this variable to
manipulate the original element later on. For instance, let's
imagine you change the label of the button from "Never clicked" to
"Clicked!" once you click on it:
App(
width: 300
height: 300
myButton = Button(
text: "Never clicked"
do: () ->
myButton.text = "Clicked!"
)
)
As you may have noticed, each element can receive some
parameters, like width, height,
bold, italic, etc. These are typically
passed when defining the element, like in the examples above. If an
element is assigned to a variable, you may have noticed that you can
change any of the parameters whenever you want, like so:
App(
myButton = Button(
backgroundColor: red
text: "Was I ever clicked?"
bold: no
do: () ->
myButton.backgroundColor = green
myButton.text = "I was clicked!"
myButton.bold = yes
)
)
Note that, when passing the parameters as we initially create the
element, we use a colon (:, e.g.,
backgroundColor: red). However, when updating the
parameter later, we use an equal sign (=, e.g.,
myButton.backgroundColor = green).
You can use a multitude of elements, and some can have nested
elements of their own. For example, you can group multiple elements
together using Section elements:
App(
width: 300
height: 300
Section(
width: 150
left: 0
align: center
myButton = Button(
text: "Never clicked"
do: () ->
myButton.text = "Clicked!"
myText.text = "That is one swell button!"
)
)
Section(
width: 150
right: 0
myText = Text(
text: "I wonder what that button does..."
)
)
)
Note that we just nested multiple Section elements
inside App! If an element can contain others, you can
nest as many as you want, mixing and matching types of elements as
needed.
App
App must always be the first element of your project.
You can have multiple Apps side by side if you wish.
App(
width: <number>
height: <number>
align: left | right | center
backgroundColor: <string>
borderColor: <string>
borderRadius: <number>
borderWidth: <number>
borderStyle: <string>
left: <number>
right: <number>
top: <number>
)
Button
Button elements represent, well, buttons. A button can
be clicked, and this can trigger some logic. This logic is defined
via a "callback", which is assigned to the
do parameter.
Button(
do: <function>
text: <string>
size: <number>
font: serif | sansSerif | cursive | monospace
color: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
bold: yes | no
italic: yes | no
backgroundColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderRadius: <number>
borderWidth: <number>
borderStyle: solid | dotted | dashed
left: <number>
right: <number>
top: <number>
width: <number>
height: <number>
)
Paragraph
A Paragraph element is simply a way to group other
elements together, usually Text elements.
Paragraph(
width: <number>
height: <number>
align: left | right | center
backgroundColor: <string>
borderColor: <string>
borderRadius: <number>
borderWidth: <number>
borderStyle: <string>
left: <number>
right: <number>
top: <number>
)
Section
Similar to a Paragraph, a Section is used
to group elements together. A Section element can
contain other Section elements, which can be useful for
creating a grid-like structure.
Section(
width: <number>
height: <number>
align: left | right | center
backgroundColor: <string>
borderColor: <string>
borderRadius: <number>
borderWidth: <number>
borderStyle: <string>
left: <number>
right: <number>
top: <number>
)
Text
As its name suggests, a Text element is used to write
text on screen.
Text(
text: <string>
size: <number>
font: serif | sansSerif | cursive | monospace
color: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
bold: yes | no
italic: yes | no
backgroundColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderRadius: <number>
borderWidth: <number>
borderStyle: solid | dotted | dashed
left: <number>
right: <number>
top: <number>
width: <number>
height: <number>
)
Link
A Link element allows you to add a, well, link to
another web page.
Link(
to: <string>
text: <string>
size: <number>
font: serif | sansSerif | cursive | monospace
color: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
bold: yes | no
italic: yes | no
backgroundColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderRadius: <number>
borderWidth: <number>
borderStyle: solid | dotted | dashed
left: <number>
right: <number>
top: <number>
width: <number>
height: <number>
)
Image
An Image element displays an image on screen. Pass the
address of the image via the url parameter. You can
also provide a short description of the image, which is
useful for accessibility.
Image(
url: <string>
description: <string>
backgroundColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderRadius: <number>
borderWidth: <number>
borderStyle: solid | dotted | dashed
left: <number>
right: <number>
top: <number>
width: <number>
height: <number>
)
Canvas
Canvas elements allow you to draw lines and shapes.
It's actually quite powerful, although Slippers only provides the
most basic helpers to get you started. If you want to draw more
complex shapes, you will need some deeper HTML and JS knowledge, and
read more about the
official HTML Canvas API.
Canvas elements only accept special child components:
moveTo(x, y): This "moves" the starting point of the
next instruction on the canvas. By default, all drawings start at
0,0 (which is the top left corner).
drawLine(x, y): This draws a straight line from the
current starting point (see moveTo()), to the
coordinates passed to the function. Once the line is drawn, the
starting point of the next instruction will be the end of the
drawn line.
drawCircle(x, y, radius): This draws a circle
centered around the passed coordinates. Once the circle is drawn,
the starting point of the next instruction will be the center of
the drawn circle.
fillCircle(x, y, radius): Like
drawCircle(), but draws a filled circle using the
canvas color.
fillRect(x, y, width, height): Draws a filled
rectangle at the given coordinates with the given dimensions,
using the canvas color.
clear(): Clears the entire canvas. Useful when you
want to redraw the canvas from scratch, for example in an
animation loop driven by a Timer.
You can change the drawing color at any time by setting
canvas.color on a canvas variable. This affects both
outlines and fills for subsequent drawing instructions.
Here is an example, drawing a simple stick figure:
App(
width: 440
height: 380
Canvas(
width: 440
height: 380
lineWidth: 4
color: black
# Head
drawCircle(220, 80, 30)
# Torso
moveTo(220, 110)
drawLine(220, 220)
# Left arm
moveTo(220, 120)
drawLine(180, 200)
# Right arm
moveTo(220, 120)
drawLine(260, 200)
# Left leg
moveTo(220, 220)
drawLine(180, 280)
# Right leg
moveTo(220, 220)
drawLine(260, 280)
)
)
Canvas(
color: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
lineWidth: <number>
align: left | center | right
backgroundColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderRadius: <number>
borderWidth: <number>
borderStyle: solid | dotted | dashed
left: <number>
right: <number>
top: <number>
width: <number>
height: <number>
)
TextField
A TextField element allows you to create different
types of text inputs, like text fields, textareas (large text
fields), and password fields.
TextField(
value: <string>
placeholder: <string>
secret: yes | no;
large: yes | no;
do: (value) ->
backgroundColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderColor: aqua | black | blue | cyan | fuchsia | gray | green | lightGray | lightGreen | lime | maroon | navy | olive | purple | red | teal | white | yellow
borderRadius: <number>
borderWidth: <number>
borderStyle: solid | dotted | dashed
left: <number>
right: <number>
top: <number>
width: <number>
height: <number>
)
Keyboard
The Keyboard element is special in that it's not
anything you can "see". Instead, it allows you to react on keys
being pressed on the keyboard. It only accepts a single parameter
up, which is a callback. This callback will receive the
key pressed as an argument, like so:
App(
myText = Text(
text: "No key pressed yet..."
)
Keyboard(
up: (key) ->
myText.text = "Pressed '" + key + "'!"
)
)
This can be used to manipulate other elements, even create little games! Here is an example where we move a square using the arrows:
App(
width: 300
height: 300
square = Section(
width: 30
height: 30
backgroundColor: black
top: 50
left: 50
)
Keyboard(
up: (key) ->
if key == "ArrowLeft"
square.left = square.left - 5
else if key == "ArrowRight"
square.left = square.left + 5
else if key == "ArrowUp"
square.top = square.top - 5
else if key == "ArrowDown"
square.top = square.top + 5
)
)
Keyboard(
up: <function>
)
Timer
Just like Keyboard, Timer is not a visual
element; you cannot "see" it. Instead, it will start a "ticker" that
will trigger a callback at regular intervals. The shortest interval
possible is 1 millisecond.
Here is an example that simply shows the amount of seconds that have ellapsed since starting the app:
App(
width: 300
height: 300
myText = Text(
text: "0s"
)
timer = Timer(
do: (ellapsed) ->
myText.text = (ellapsed / 1000) + "s"
)
timer.start()
)
Note that we have to assign the Timer to a variable,
and explicitly call .start(). Unless we start it, the
timer will not execute.
Once assigned to a variable, a Timer can be started
(.start()), stopped (.stop()), or
restarted (.restart()). It can also be reinitialized
(.reset()).
The Timer will execute once a second by default. This
frequency can be changed by the freq parameter, which
is a number expressed in milliseconds.
Timer(
freq: <number>
do: <function>
)