🎨 Lesson 8: Circles, Loops & Art

Where a loop and a canvas together make something you could not draw by hand

← Back to Web Coding

⭕ Circles

There is no circle(). There is arc(), which draws a slice of a circle — and a whole circle is just a slice that goes all the way round.

const ctx = document.getElementById("board").getContext("2d"); ctx.fillStyle = "crimson"; ctx.beginPath(); ctx.arc(80, 120, 50, 0, Math.PI * 2); ctx.fill(); ctx.strokeStyle = "#1a5490"; ctx.lineWidth = 5; ctx.beginPath(); ctx.arc(220, 120, 50, 0, Math.PI * 2); ctx.stroke(); Try it — this is live
80, 120the middle of the circle
50the radius — half the width
0, Math.PI * 2start angle, end angle

Math.PI * 2 is a full turn, measured in radians. You do not have to understand radians to use it — 0, Math.PI * 2 means all the way round, and that is the only pair you need for a whole circle.

🍕 Half a turn is a semicircle

Try 0, Math.PI instead and you get half. 0, Math.PI / 2 gives you a quarter — a pie slice, once you fill() it.

🔁 The trick: a loop that draws

Here is where drawing with code beats drawing by hand. You do not write a hundred shapes. You write one shape and a loop that moves it.

const ctx = document.getElementById("board").getContext("2d"); for (let i = 0; i < 10; i++) { ctx.fillStyle = "#1a5490"; ctx.fillRect(10 + i * 30, 100, 20, 40); } Try it — this is live

The whole picture is 10 + i * 30. As i counts 0, 1, 2, the x jumps 10, 40, 70 — evenly spaced, for free. Change the 10 to 30 and every square moves at once.

const ctx = document.getElementById("board").getContext("2d"); for (let i = 0; i < 12; i++) { ctx.fillStyle = `hsl(${i * 30}, 80%, 55%)`; ctx.beginPath(); ctx.arc(30 + i * 22, 120, 10 + i * 2, 0, Math.PI * 2); ctx.fill(); } Try it — this is live

🌈 hsl() is the easy rainbow

hsl(hue, saturation, lightness) — the hue is an angle round a colour wheel from 0 to 360. Multiply it by the loop counter and you get a rainbow without picking a single colour by hand.

🔲 A loop inside a loop

One loop gives you a row. A loop inside a loop gives you a grid.

const ctx = document.getElementById("board").getContext("2d"); for (let row = 0; row < 6; row++) { for (let col = 0; col < 8; col++) { if ((row + col) % 2 === 0) { ctx.fillStyle = "#2c3e50"; } else { ctx.fillStyle = "#e8e8e8"; } ctx.fillRect(col * 40, row * 40, 40, 40); } } Try it — this is live

Forty-eight squares from eight lines. The chessboard pattern is the (row + col) % 2 — neighbouring squares always differ by one, so they always land on opposite colours.

🎲 A bit of randomness

const ctx = document.getElementById("board").getContext("2d"); for (let i = 0; i < 40; i++) { const x = Math.random() * 320; const y = Math.random() * 240; const size = Math.random() * 20 + 4; ctx.fillStyle = `hsl(${Math.random() * 360}, 70%, 60%)`; ctx.beginPath(); ctx.arc(x, y, size, 0, Math.PI * 2); ctx.fill(); } Try it — this is live

Math.random() gives a number from 0 up to 1. Multiply it to stretch it: Math.random() * 320 lands anywhere across the canvas.

🔄 Run it twice

Press Run again and you get a different picture from exactly the same code. Every run is a new one — which is how every starfield and every snowstorm in every game is made.

🧰 Wrapping a shape in a function

Once a shape has a name you can scatter it about without repeating yourself:

const ctx = document.getElementById("board").getContext("2d"); function star(x, y, size, colour) { ctx.fillStyle = colour; ctx.beginPath(); for (let i = 0; i < 10; i++) { const angle = i * Math.PI / 5 - Math.PI / 2; const reach = (i % 2 === 0) ? size : size / 2.4; ctx.lineTo(x + Math.cos(angle) * reach, y + Math.sin(angle) * reach); } ctx.closePath(); ctx.fill(); } star(70, 80, 40, "gold"); star(180, 140, 55, "crimson"); star(270, 60, 30, "#4a90d9"); Try it — this is live

Three stars, three sizes, three colours — and the shape itself is written once. That is the same idea as Lesson 5's functions, pointed at a picture.

✅ What you learned

  • arc(x, y, radius, 0, Math.PI * 2) is a whole circle — wrap it in beginPath and fill.
  • A loop plus i * spacing makes a row; a loop inside a loop makes a grid.
  • hsl(hue, …) gives you a rainbow from the loop counter.
  • Math.random() gives 0 to 1 — multiply to stretch it.
  • A shape in a function can be used anywhere, at any size.
← Lesson 7: Drawing on a Canvas Back to the Web Coding Hub →