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 sizebackground(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-255rgba(r, g, b, a)- a is 0-1hsl(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 radiansscale(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 positionmousePressed- is mouse button down?key- last key pressedkeyPressed- is any key down?frame- current frame number
Utilities
print(value)- output to consolelen(array)push(array, value)pop(array)