Welcome to Bloom

Bloom is a programming language for making visual things. If you've never programmed before, you're in the right place. If you have, you'll find Bloom refreshingly simple.

In the next few minutes, you'll learn how to draw shapes, add colors, create animations, and respond to mouse clicks. Each section has a live editor where you can experiment. Change the code, see what happens. That's the best way to learn.

Your First Sketch

Let's start by drawing a circle. Every Bloom program can have two special parts: setup runs once at the beginning, and draw runs over and over, about 60 times per second.

Here's a simple sketch. Try changing the numbers and see what happens:

fn setup() { size(200, 200) } fn draw() { background(white) fill(blue) circle(100, 100, 40) }

The circle(100, 100, 40) draws a circle at position (100, 100) with a radius of 40. Try changing 100, 100 to move it around, or change 40 to make it bigger or smaller.

Shapes

Bloom gives you a handful of basic shapes to work with. Each shape needs different information to know where and how big to draw itself.

Circles and Ellipses

A circle needs a center point (x, y) and a radius. An ellipse is like a stretched circle - it needs a center point plus width and height.

fn setup() { size(200, 200) } fn draw() { background(white) fill(blue) circle(60, 100, 30) fill(purple) ellipse(140, 100, 60, 80) }

Rectangles

A rect needs a top-left corner (x, y), then width and height.

fn setup() { size(200, 200) } fn draw() { background(white) fill(orange) rect(40, 40, 50, 80) fill(teal) rect(110, 60, 60, 60) }

Lines and Triangles

Lines go from one point to another. Triangles need three corner points.

fn setup() { size(200, 200) } fn draw() { background(white) stroke(red) strokeWeight(3) line(20, 20, 180, 180) fill(green) triangle(100, 30, 40, 170, 160, 170) }

Colors

Bloom comes with a set of named colors you can use right away: red, blue, green, yellow, orange, purple, pink, cyan, white, black, gray, and more.

fn setup() { size(200, 200) } fn draw() { background(white) fill(red) circle(50, 50, 30) fill(green) circle(100, 100, 30) fill(blue) circle(150, 150, 30) }

Custom Colors

Want more control? Use rgb() to mix your own colors. Each value goes from 0 to 255: red, green, and blue.

fn setup() { size(200, 200) } fn draw() { background(rgb(30, 30, 50)) fill(rgb(255, 100, 100)) circle(60, 100, 40) fill(rgb(100, 200, 255)) circle(140, 100, 40) }

Transparency

Add a fourth number to rgba() for transparency. It goes from 0 (invisible) to 1 (solid).

fn setup() { size(200, 200) } fn draw() { background(white) fill(rgba(255, 0, 0, 0.7)) circle(80, 80, 50) fill(rgba(0, 0, 255, 0.7)) circle(120, 120, 50) }

Styling

Shapes have two parts: the fill (inside color) and the stroke (outline). You can control both independently.

fn setup() { size(200, 200) } fn draw() { background(white) fill(yellow) stroke(orange) strokeWeight(4) circle(70, 100, 40) noFill() stroke(blue) strokeWeight(2) circle(130, 100, 40) }

Use noFill() to draw just the outline, or noStroke() to draw without an outline.

Variables

Variables let you store values and use them later. Create one with let and give it a name.

let x = 100 let size = 60 fn setup() { size(200, 200) } fn draw() { background(white) fill(blue) circle(x, 100, size) }

Try changing the values of x and size at the top. Variables make it easy to adjust your sketch without hunting through all the code.

Animation

Here's where it gets fun. Since draw() runs over and over, you can change values each frame to create motion.

let x = 0 fn setup() { size(200, 200) } fn draw() { background(white) fill(blue) circle(x, 100, 20) x = x + 2 if x > 200 { x = 0 } }

Each frame, we add 2 to x, making the circle move right. When it goes past the edge, we reset it to 0.

Using frame

Bloom gives you a built-in variable called frame that counts up each frame. Combined with sin() and cos(), you can create smooth, looping motion.

fn setup() { size(200, 200) } fn draw() { background(rgb(30, 30, 50)) let x = 100 + sin(frame * 0.05) * 50 let y = 100 + cos(frame * 0.05) * 50 fill(rgb(255, 150, 100)) circle(x, y, 20) }

Making Decisions

Programs can make choices using if. If a condition is true, the code inside the braces runs.

let x = 0 let speed = 2 fn setup() { size(200, 200) } fn draw() { background(white) if x > 100 { fill(red) } else { fill(blue) } circle(x, 100, 20) x = x + speed if x > 200 { x = 0 } }

The circle changes color when it passes the middle of the canvas.

Loops

Loops let you repeat things without writing the same code over and over. A for loop is perfect for drawing patterns.

fn setup() { size(200, 200) } fn draw() { background(white) for i in 0..5 { fill(blue) circle(40 + i * 30, 100, 20) } }

The loop runs 5 times, with i going from 0 to 4. Each time, we draw a circle at a different position.

Nested Loops

Put a loop inside a loop to create grids.

fn setup() { size(200, 200) } fn draw() { background(white) for row in 0..5 { for col in 0..5 { let x = 30 + col * 35 let y = 30 + row * 35 fill(hsl(row * 40 + col * 20, 70, 60)) circle(x, y, 12) } } }

Functions

When you find yourself writing the same code in multiple places, it's time to make a function. Functions bundle up code so you can reuse it.

fn setup() { size(200, 200) } fn draw() { background(white) flower(50, 50) flower(100, 120) flower(150, 70) } fn flower(x, y) { fill(pink) circle(x - 15, y, 12) circle(x + 15, y, 12) circle(x, y - 15, 12) circle(x, y + 15, 12) fill(yellow) circle(x, y, 10) }

Now you can draw flowers anywhere by just calling flower(x, y). Try adding more flowers or changing the flower function.

Mouse

Bloom tracks the mouse position in two variables: mouseX and mouseY. You can also check if the mouse button is pressed with mousePressed.

fn setup() { size(200, 200) } fn draw() { background(rgb(30, 30, 50)) if mousePressed { fill(red) } else { fill(blue) } circle(mouseX, mouseY, 30) }

Move your mouse over the canvas. Click to change the color.

Drawing App

Here's a simple drawing program. Notice we removed background() from draw, so each frame builds on the last.

fn setup() { size(200, 200) background(white) } fn draw() { if mousePressed { fill(blue) noStroke() circle(mouseX, mouseY, 8) } }

Keyboard

Use keyPressed to check if any key is down, and key to see which key it is.

let x = 100 let y = 100 fn setup() { size(200, 200) } fn draw() { background(white) if keyPressed { if key == "ArrowUp" { y = y - 3 } if key == "ArrowDown" { y = y + 3 } if key == "ArrowLeft" { x = x - 3 } if key == "ArrowRight" { x = x + 3 } } fill(green) circle(x, y, 20) }

Click on the canvas first to give it focus, then use arrow keys to move.

Reference

Here's a quick reference of everything Bloom offers.

Canvas

  • size(width, height) - Set canvas size
  • background(color) - Clear with a color

Shapes

  • circle(x, y, radius)
  • ellipse(x, y, width, height)
  • rect(x, y, width, height)
  • line(x1, y1, x2, y2)
  • triangle(x1, y1, x2, y2, x3, y3)
  • point(x, y)
  • text(str, x, y)

Colors

  • rgb(r, g, b) - values 0-255
  • rgba(r, g, b, a) - a is 0-1
  • hsl(h, s, l) - h: 0-360, s/l: 0-100
  • Named: red, blue, green, yellow, orange, purple, pink, cyan, white, black, gray, teal

Styling

  • fill(color)
  • stroke(color)
  • strokeWeight(width)
  • noFill()
  • noStroke()

Transforms

  • translate(x, y)
  • rotate(angle) - in radians
  • scale(x, y)
  • push() / pop() - save/restore state

Math

  • sin(x), cos(x), tan(x)
  • sqrt(x), pow(x, y), abs(x)
  • floor(x), ceil(x), round(x)
  • min(a, b), max(a, b)
  • random(), random(max), random(min, max)
  • map(value, start1, stop1, start2, stop2)
  • lerp(a, b, t)
  • Constants: PI, TWO_PI, HALF_PI

Input

  • mouseX, mouseY - mouse position
  • mousePressed - is mouse button down?
  • key - last key pressed
  • keyPressed - is any key down?
  • frame - current frame number

Utilities

  • print(value) - output to console
  • len(array)
  • push(array, value)
  • pop(array)