package elm_playground
Entry points
The main entry points of this library are:
The important types are:
Basic types
Numbers
A number like 1
or 3.14
or -120
.
It is more flexible to use float
rather han int
for graphical operations. Consider using open Basics
to have the +
, -
, and other arithmetic operators working on floats instead of having to use +.
, -.
, etc.
Time
Create an angle that cycles from 0 to 360 degrees over time.
Here is an animation
with a spinning triangle:
open Playground
let view time =
[ triangle orange 50
|> rotate (spin 8 time)
]
let app =
animation view
let main = Playground.run_app app
It will do a full rotation once every eight seconds. Try changing the 8
to a 2
to make it do a full rotation every two seconds. It moves a lot faster!
Smoothly wave between two numbers.
Here is an animation
with a circle that resizes:
open Playground
view time =
[ circle lightBlue (wave 50 90 7 time)
]
let app =
animation view
let main = Playground.run_app app
The radius of the circle will cycles between 50 and 90 every seven seconds. It kind of looks like it is breathing.
Zig zag between two numbers.
Here is an animation
with a rectangle that tips back and forth:
open Playground
view time =
[ rectangle lightGreen 20 100
|> rotate (zigzag -20 20 4 time)
]
let app =
animation view
let main = Playground.run_app app
It gets rotated by an angle. The angle cycles from -20 degrees to 20 degrees every four seconds.
Colors
type color = Color.t
Represents a color.
The colors below, like red
and green
, come from the Tango palette. It provides a bunch of aesthetically reasonable colors. Each color comes with a light and dark version, so you always get a set like lightYellow
, yellow
, and darkYellow
.
val rgb : int -> int -> int -> color
RGB stands for Red-Green-Blue. With these three parts, you can create any color you want. For example:
let brightBlue = rgb 18 147 216
let brightGreen = rgb 119 244 8
let brightPurple = rgb 94 28 221
Each number needs to be between 0 and 255.
It can be hard to figure out what numbers to pick, so try using a color picker like paletton to find colors that look nice together. Once you find nice colors, click on the color previews to get their RGB values.
val white : color
val black : color
val red : color
val green : color
val blue : color
val yellow : color
val brown : color
val lightYellow : color
val lightPurple : color
val gray : color
val darkGray : color
Shapes
Basic Shapes
Make circles:
let dot = circle red 10
let sun = circle yellow 300
You give a color and then the radius. So the higher the number, the larger the circle.
Make ovals:
let football = oval brown 200 100
You give the color, and then the width and height. So our football
example is 200 pixels wide and 100 pixels tall.
Make rectangles. This example makes a red cross:
open Playground
let app =
picture
[ rectangle red 20 60
; rectangle red 60 20
]
let main = Playground.run_app app
You give the color, width, and then height. So the first shape is vertical part of the cross, the thinner and taller part.
Make squares. Here are two squares combined to look like an empty box:
open Playground
let app =
picture
[ square purple 80
; square white 60
]
let main = Playground.run_app app
The number you give is the dimension of each side. So that purple square would be 80 pixels by 80 pixels.
Make triangles. So if you wanted to draw the Egyptian pyramids, you could do a simple version like this:
open Playground
let app =
picture
[ triangle darkYellow 200
]
let main = Playground.run_app app
The number is the "radius", so the distance from the center to each point of the pyramid is 200
. Pretty big!
Make pentagons:
open Playground
let app =
picture
[ pentagon darkGrey 100
]
let main = Playground.run_app app
You give the color and then the radius. So the distance from the center to each of the five points is 100 pixels.
Make hexagons:
open Playground
let app =
picture
[ hexagon lightYellow 50
]
let main = Playground.run_app app
The number is the radius, the distance from the center to each point.
If you made more hexagons, you could move
them around to make a honeycomb pattern!
Make octogons:
open Playground
let app =
picture
[ octagon red 100
]
let main = Playground.run_app app
You give the color and radius, so each point of this stop sign is 100 pixels from the center.
Make any shape you want! Here is a very thin triangle:
open Playground
let app =
picture
[ polygon black [ (-10,-20), (0,100), (10,-20) ]
]
let main = Playground.run_app app
Note: If you rotate
a polygon, it will always rotate around (0,0)
. So it is best to build your shapes around that point, and then use move
or group
so that rotation makes more sense.
Images
Add some image from the internet:
open Playground
let app =
picture
[ image 96 96 "https://elm-lang.org/images/turtle.gif"
]
let main = Playground.run_app app
You provide the width, height, and then the URL of the image you want to show.
Words
Show some words!
open Playground
let app =
picture
[ words black "Hello! How are you?"
]
let main = Playground.run_app app
You can use scale
to make the words bigger or smaller.
Groups
Put shapes together so you can move
and rotate
them as a group. Maybe you want to put a bunch of stars in the sky:
open Playground
let star =
group
[ triangle yellow 20
; triangle yellow 20
|> rotate 180
]
let app =
picture
[ star
|> move 100 100
|> rotate 5
; star
|> move -120 40
|> rotate 20
; star
|> move 80 -150
|> rotate 32
; star
|> move -90 -30
|> rotate -16
]
let main = Playground.run_app app
Move Shapes
Move a shape by some number of pixels:
open Playground
let app =
picture
[ square red 100
|> move -60 60
; square yellow 100
|> move 60 60
; square green 100
|> move 60 -60
; square blue 100
|> move -60 -60
]
let main = Playground.run_app app
Move shapes to the left.
open Playground
let app =
picture
[ circle yellow 10
|> moveLeft 80
|> moveUp 30
]
let main = Playground.run_app app
Move shapes to the right.
open Playground
let app =
picture
[ square purple 20
|> moveRight 80
|> moveDown 100
]
let main = Playground.run_app app
Move a shape up by some number of pixels. So if you wanted to make a tree you could move the leaves up above the trunk:
open Playground
let app =
picture
[ rectangle brown 40 200
, circle green 100
|> moveUp 180
]
let main = Playground.run_app app
Move a shape down by some number of pixels. So if you wanted to put the sky above the ground, you could move the sky up and the ground down:
open Playground
let app =
picture
[ rectangle lightBlue 200 100
|> moveUp 50
; rectangle lightGreen 200 100
|> moveDown 50
]
let main = Playground.run_app app
Move the x
coordinate of a shape by some amount. Here is a square that moves back and forth:
open Playground
view time =
[ square purple 20
|> move_x (wave 4 -200 200 time)
]
let app =
animation view
let main = Playground.run_app app
Using move_x
feels a bit nicer here because the movement may be positive or negative.
Move the y
coordinate of a shape by some amount. Maybe you want to make grass along the bottom of the screen:
open Playground
let update computer memory =
memory
let view computer count =
[ rectangle green computer.screen.width 100
|> move_y computer.screen.bottom
]
let app =
game view update 0
let main = Playground.run_app app
Using move_y
feels a bit nicer when setting things relative to the bottom or top of the screen, since the values are negative sometimes.
Customize Shapes
Make a shape bigger or smaller. So if you wanted some words
to be larger, you could say:
open Playground
let app =
picture
[ words black "Hello, nice to see you!"
|> scale 3
]
let main = Playground.run_app app
Rotate shapes in degrees.
open Playground
let app =
picture
[ words black "These words are tilted!"
|> rotate 10
]
let main = Playground.run_app app
The degrees go counter-clockwise to match the direction of the unit circle.
Fade a shape. This lets you make shapes see-through or even completely invisible. Here is a shape that fades in and out:
open Playground
view time =
[ square orange 30
; square blue 200
|> fade (zigzag 0 1 3 time)
]
let app =
animation view
let main = Playground.run_app app
The number has to be between 0
and 1
, where 0
is totally transparent and 1
is completely solid.
Computer
Get the dimensions of the screen. If the screen is 800 by 600, you will see a value like this:
{ width = 800
; height = 600
; top = 300
; left = -400
; right = 400
; bottom = -300
}
This can be nice when used with move_y
if you want to put something on the bottom of the screen, no matter the dimensions.
Figure out what is going on with the mouse.
You could draw a circle around the mouse with a program like this:
open Playground
let view computer memory =
[ circle yellow 40
|> move_x computer.mouse.x
|> move_y computer.mouse.y
]
let update computer memory =
memory
let app =
game view update 0
let main = Playground.run_app app
You could also use computer.mouse.down
to change the color of the circle while the mouse button is down.
type keyboard = {
kup : bool;
kdown : bool;
kleft : bool;
kright : bool;
kw : bool;
ks : bool;
ka : bool;
kd : bool;
kspace : bool;
kenter : bool;
kshift : bool;
kbackspace : bool;
keys : string Set_.t;
}
Figure out what is going on with the keyboard.
If someone is pressing the UP and RIGHT arrows, you will see a value like this:
{ kup = True, kdown = False, kleft = False, kright = True
, kspace = False, kenter = False, kshift = False, kbackspace = False
, keys = Set.fromList ["ArrowUp","ArrowRight"]
}
So if you want to move a character based on arrows, you could write an update like this:
let update computer y =
if computer.keyboard.kup then
y + 1
else
y
Check out to_x
and to_y
which make this even easier!
Note: The keys
set will be filled with the name of all keys which are down right now. So you will see things like "a"
, "b"
, "c"
, "1"
, "2"
, "Space"
, and "Control"
in there. Check out this list to see the names used for all the different special keys! From there, you can use Set.member
to check for whichever key you want. E.g. Set.member "Control" computer.keyboard.keys
.
Turn the LEFT and RIGHT arrows into a number.
to_x { left = False, right = False, ... } == 0
to_x { left = True , right = False, ... } == -1
to_x { left = False, right = True , ... } == 1
to_x { left = True , right = True , ... } == 0
So to make a square move left and right based on the arrow keys, we could say:
open Playground
let view computer x =
[ square green 40
|> move_x x
]
let update computer x =
x + to_x computer.keyboard
let app =
game view update 0
let main = Playground.run_app app
Turn the UP and DOWN arrows into a number.
to_y { up = False, down = False, ... } == 0
to_y { up = True , down = False, ... } == 1
to_y { up = False, down = True , ... } == -1
to_y { up = True , down = True , ... } == 0
This can be used to move characters around in games just like to_x
:
open Playground
let view computer (x,y) =
[ square blue 40
|> move x y
]
let update computer (x,y) =
( x + to_x computer.keyboard
, y + to_y computer.keyboard
)
let app =
game view update (0,0)
let main = Playground.run_app app
If you just use to_x
and to_y
, you will move diagonal too fast. You will go right at 1 pixel per update, but you will go up/right at 1.41421 pixels per update.
So to_xy
turns the arrow keys into an (x,y)
pair such that the distance is normalized:
to_xy { up = True , down = False, left = False, right = False, ... } == (1, 0)
to_xy { up = True , down = False, left = False, right = True , ... } == (0.707, 0.707)
to_xy { up = False, down = False, left = False, right = True , ... } == (0, 1)
Now when you go up/right, you are still going 1 pixel per update.
open Playground
let view computer (x,y) =
[ square green 40
|> move x y
]
let update computer (x,y) =
let
(dx,dy) = to_xy computer.keyboard
in
(x + dx, y + dy)
let app =
game view update (0,0)
let main = Playground.run_app app
When writing a game
, you can look up all sorts of information about your computer:
mouse
- Where is the mouse right now?keyboard
- Are the arrow keys down?screen
- How wide is the screen?time
- What time is it right now?
So you can use expressions like computer.mouse.x
and computer.keyboard.kenter
in games where you want some mouse or keyboard interaction.
val initial_computer : computer
The Application
Playgrounds
Pictures
Make a picture! Here is a picture of a triangle with an eyeball:
open Playground
let app =
picture
[ triangle green 150
; circle white 40
; circle black 10
]
let main = Playground.run_app app
Animations
Create an animation!
Once you get comfortable using picture
to layout shapes, you can try out an animation
. Here is square that zigzags back and forth:
open Playground
view time =
[ square blue 40
|> move_x (zigzag -100 100 2 time)
]
let app =
animation view
let main = Playground.run_app app
We need to define a view
to make our animation work.
Within view
we can use functions like spin
, wave
, and zigzag
to move and rotate our shapes.
Games
val game :
(computer -> 'memory -> shape list) ->
(computer -> 'memory -> 'memory) ->
'memory ->
('memory game, msg) app
Create a game!
Once you get comfortable with animation
, you can try making a game with the keyboard and mouse. Here is an example of a green square that just moves to the right:
open Playground
let view computer offset =
[ square green 40
|> moveRight offset
]
let update computer offset =
offset + 0.03
let app =
game view update 0
let main = Playground.run_app app
This shows the three important parts of a game:
memory
- makes it possible to store information. So with our green square, we save theoffset
in memory. It starts out at0
.view
- lets us say which shapes to put on screen. So here we move our square right by theoffset
saved in memory.update
- lets us update the memory. We are incrementing theoffset
by a tiny amount on each frame.
The update
function is called about 60 times per second, so our little changes to offset
start to add up pretty quickly!
This game is not very fun though! Making a game
also gives you access to the Computer
, so you can use information about the mouse
and keyboard
to make it interactive! So here is a red square that moves based on the arrow keys:
open Playground
let view computer (x,y) =
[ square red 40
|> move x y
]
let update computer (x,y) =
( x + to_x computer.keyboard
, y + to_y computer.keyboard
)
let app =
game view update (0,0)
let main = Playground.run_app app
Notice that in the update
we use information from the keyboard to update the x
and y
values. These building blocks let you make pretty fancy games!