package elm_playground

  1. Overview
  2. Docs

Entry points

The main entry points of this library are:

The important types are:

Basic types

Numbers

type number = float

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

type time =
  1. | Time of number

The current time.

Helpful when making an animation with functions like spin, wave, and zigzag.

val spin : number -> time -> number

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!

val wave : number -> number -> number -> time -> number

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.

val zigzag : number -> number -> number -> time -> number

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

type shape = {
  1. x : number;
  2. y : number;
  3. angle : number;
  4. scale : number;
  5. alpha : number;
  6. form : form;
}

Shapes help you make a picture, animation, or game.

Read on to see examples of circle, rectangle, words, image, and many more!

and form =
  1. | Circle of color * number
  2. | Oval of color * number * number
  3. | Rectangle of color * number * number
  4. | Ngon of color * int * number
  5. | Polygon of color * (number * number) list
  6. | Image of number * number * string
  7. | Words of color * string
  8. | Group of shape list

Basic Shapes

val circle : color -> number -> shape

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.

val oval : color -> number -> number -> shape

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.

val rectangle : color -> number -> number -> shape

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.

val square : color -> number -> shape

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.

val triangle : color -> number -> shape

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!

val pentagon : color -> number -> shape

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.

val hexagon : color -> number -> shape

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!

val octagon : color -> number -> shape

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.

val polygon : color -> (number * number) list -> shape

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

val image : number -> number -> string -> shape

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

val words : color -> string -> shape

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

val group : shape list -> shape

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

val move : number -> number -> shape -> shape

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
val move_left : number -> shape -> shape

Move shapes to the left.

open Playground

let app =
  picture
    [ circle yellow 10
        |> moveLeft 80
        |> moveUp 30
    ]

let main = Playground.run_app app
val move_right : number -> shape -> shape

Move shapes to the right.

open Playground

let app =
  picture
    [ square purple 20
        |> moveRight 80
        |> moveDown 100
    ]

let main = Playground.run_app app
val move_up : number -> shape -> shape

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
val move_down : number -> shape -> shape

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
val move_x : number -> shape -> shape

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.

val move_y : number -> shape -> shape

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

val scale : number -> shape -> shape

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
val rotate : number -> shape -> shape

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.

val fade : number -> shape -> shape

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

val default_width : float
val default_height : float
type screen = {
  1. width : number;
  2. height : number;
  3. top : number;
  4. left : number;
  5. right : number;
  6. bottom : number;
}

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.

val to_screen : number -> number -> screen
type mouse = {
  1. mx : number;
  2. my : number;
  3. mdown : bool;
  4. mclick : bool;
}

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 = {
  1. kup : bool;
  2. kdown : bool;
  3. kleft : bool;
  4. kright : bool;
  5. kw : bool;
  6. ks : bool;
  7. ka : bool;
  8. kd : bool;
  9. kspace : bool;
  10. kenter : bool;
  11. kshift : bool;
  12. kbackspace : bool;
  13. 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.

val to_x : keyboard -> number

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
val to_y : keyboard -> number

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
val to_x2 : keyboard -> number
val to_y2 : keyboard -> number
val to_xy : keyboard -> number * number

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
type computer = {
  1. mouse : mouse;
  2. keyboard : keyboard;
  3. screen : screen;
  4. time : time;
}

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

type ('model, 'msg) app = {
  1. init : unit -> 'model * 'msg Cmd.t;
  2. update : 'msg -> 'model -> 'model * 'msg Cmd.t;
  3. view : 'model -> shape list;
  4. subscriptions : 'model -> 'msg Sub.t;
}

Playgrounds

Pictures

type msg1 =
  1. | Resized1 of int * int
val picture : shape list -> (screen, msg1) app

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

type msg =
  1. | Tick of number
  2. | Resized of int * int
  3. | KeyChanged of bool * string
  4. | MouseMove of number * number
  5. | MouseClick
  6. | MouseButton of bool
type animation
val animation : (time -> shape list) -> (animation, msg) app

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

type 'memory game
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:

  1. memory - makes it possible to store information. So with our green square, we save the offset in memory. It starts out at 0.
  2. view - lets us say which shapes to put on screen. So here we move our square right by the offset saved in memory.
  3. update - lets us update the memory. We are incrementing the offset 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!

OCaml

Innovation. Community. Security.