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.
Noise
Perlin noise is a special kind of randomness that flows smoothly.
Unlike random() which jumps around, noise()
creates organic, natural-looking variation. It's perfect for terrain,
clouds, textures, and organic movement.
fn setup() {
size(200, 200)
}
fn draw() {
background(rgb(30, 30, 50))
for i in 0..40 {
let x = i * 5
let n = noise(i * 0.1 + frame * 0.02)
let y = 100 + n * 80 - 40
fill(hsl(200 + n * 60, 80, 60))
circle(x, y, 4)
}
}
The noise() function takes 1 to 3 numbers and returns a value between 0 and 1.
Nearby inputs give similar outputs, which is what makes it flow smoothly.
fn setup() {
size(200, 200)
}
fn draw() {
background(white)
for y in 0..20 {
for x in 0..20 {
let n = noise(x * 0.2, y * 0.2, frame * 0.01)
fill(hsl(0, 0, n * 100))
rect(x * 10, y * 10, 10, 10)
}
}
}Color Palettes
Choosing colors that work well together is hard. Bloom includes several
curated color palettes you can use right away with palette().
fn setup() {
size(200, 200)
}
fn draw() {
background(rgb(30, 30, 50))
for i in 0..5 {
fill(palette("sunset", i))
circle(30 + i * 35, 60, 15)
}
for i in 0..5 {
fill(palette("ocean", i))
circle(30 + i * 35, 100, 15)
}
for i in 0..5 {
fill(palette("forest", i))
circle(30 + i * 35, 140, 15)
}
}
Available palettes: sunset, ocean, forest,
fire, pastel, mono, neon, earth.
Blending Colors
Use lerpColor() to smoothly blend between two colors.
fn setup() {
size(200, 200)
}
fn draw() {
background(white)
for i in 0..10 {
let t = i / 9
let c = lerpColor("#ff6b6b", "#4ecdc4", t)
fill(c)
rect(i * 20, 80, 20, 40)
}
}Complex Shapes
Beyond basic shapes, Bloom provides polygon() and star()
for more interesting geometry.
fn setup() {
size(200, 200)
}
fn draw() {
background(rgb(30, 30, 50))
fill(rgb(100, 200, 255))
polygon(60, 100, 30, 6)
fill(rgb(255, 200, 100))
polygon(140, 100, 30, 8)
}
polygon(x, y, radius, sides) draws a regular polygon.
Try different numbers of sides: 3 for triangle, 5 for pentagon, 6 for hexagon.
Stars
fn setup() {
size(200, 200)
}
fn draw() {
background(rgb(20, 20, 40))
fill(rgb(255, 220, 100))
star(60, 100, 35, 15, 5)
fill(rgb(255, 150, 200))
star(140, 100, 35, 20, 8)
}
star(x, y, outerRadius, innerRadius, points) draws a star shape.
The inner radius determines how pointy the star is.
Easing and Motion
Real things don't move at constant speed. They accelerate, decelerate, and bounce. Bloom provides easing functions and oscillators to create natural-feeling motion.
Oscillators
oscillate() smoothly moves between two values automatically.
fn setup() {
size(200, 200)
}
fn draw() {
background(white)
let size1 = oscillate(20, 50)
let size2 = oscillate(20, 50, 1.5)
let size3 = oscillate(20, 50, 2, 1)
fill(red)
circle(50, 100, size1)
fill(green)
circle(100, 100, size2)
fill(blue)
circle(150, 100, size3)
}Easing Functions
Easing functions transform linear motion (0 to 1) into more interesting curves.
fn setup() {
size(200, 200)
}
fn draw() {
background(white)
let t = (frame % 120) / 120
let linear = t * 160
let easeI = easeIn(t) * 160
let easeO = easeOut(t) * 160
let easeIO = easeInOut(t) * 160
stroke(gray)
strokeWeight(1)
line(20, 40, 20, 160)
line(180, 40, 180, 160)
noStroke()
fill(red)
circle(20 + linear, 50, 8)
fill(green)
circle(20 + easeI, 90, 8)
fill(blue)
circle(20 + easeO, 130, 8)
fill(purple)
circle(20 + easeIO, 170, 8)
}Grids
The grid() function makes it easy to create patterns.
It calls a function for each cell, providing the column, row, and center position.
fn setup() {
size(200, 200)
}
fn draw() {
background(white)
grid(5, 5, 40, 40, fn(col, row, x, y) {
let hue = (col + row) * 30
fill(hsl(hue, 70, 60))
circle(x, y, 15)
})
}Combined with noise and animation, grids can create mesmerizing effects.
fn setup() {
size(200, 200)
}
fn draw() {
background(rgb(20, 20, 40))
grid(8, 8, 25, 25, fn(col, row, x, y) {
let n = noise(col * 0.3, row * 0.3, frame * 0.02)
let size = 5 + n * 15
fill(palette("ocean", floor(n * 5)))
circle(x, y, size)
})
}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()
Advanced Shapes
polygon(x, y, radius, sides)- regular polygonstar(x, y, outerRadius, innerRadius, points)arc(x, y, w, h, startAngle, stopAngle)bezier(x1, y1, cx1, cy1, cx2, cy2, x2, y2)
Transforms
translate(x, y)rotate(angle)- in radiansscale(x, y)pushMatrix()/popMatrix()- save/restore state
Math
sin(x),cos(x),tan(x),atan2(y, 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)constrain(value, min, max)- clamp to rangedist(x1, y1, x2, y2)- distance between pointsnoise(x),noise(x, y),noise(x, y, z)- Perlin noise (0-1)- Constants:
PI,TWO_PI,HALF_PI
Animation Helpers
oscillate(min, max, speed?, offset?)- smooth oscillationbounce(min, max, speed?)- bouncing motionpulse(speed?)- 0 to 1 pulsingwave(frequency?, amplitude?, offset?)- sine waveeaseIn(t),easeOut(t),easeInOut(t)- easing (0-1)smoothstep(edge0, edge1, x)- smooth transitionpingpong(t, length)- back and forthrepeat(t, length)- wrap value
Color Helpers
palette(name, index)- get color from palettepaletteSize(name)- number of colors in palettelerpColor(color1, color2, t)- blend colors- Palettes: sunset, ocean, forest, fire, pastel, mono, neon, earth
Grid Helper
grid(cols, rows, cellW, cellH, callback)- iterate over grid
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)