Chapter 32: Canvas Tutorial
Canvas the way a good private tutor would teach it: slowly, clearly, with small complete examples, mental models you can actually remember, and no magic hand-waving.
We will build understanding step by step — not just throw 300 lines of code at you.
HTML5 Canvas – Complete Beginner-to-Confident Tutorial (2025–2026 edition – modern best practices)
0. First mental model – Canvas is not SVG
Most people who come from SVG get confused, so let’s clear this immediately.
| Question | Canvas answer | SVG answer |
|---|---|---|
| Is it vector or bitmap? | Bitmap (pixels) | Vector (math shapes) |
| Does it scale perfectly forever? | No – enlarges → pixelates | Yes – always sharp |
| How many objects exist in memory? | Basically one bitmap image | One DOM element per shape |
| Can I click on individual shapes? | Only if you keep track of coordinates | Yes – real DOM elements |
| Best for | Games, particles, charts with 5,000+ points, real-time drawing, video filters, 3D projections | Icons, logos, diagrams, maps, interactive infographics |
| Animation style | You redraw everything every frame | Change attributes → browser redraws only what’s needed |
Rule of thumb 2026 → Use Canvas when you need high performance with thousands of moving things → Use SVG when you need sharp vectors + easy interactivity
1. Absolute minimal working Canvas (copy → paste → run)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Canvas – First Drawing</title> <style> canvas { border: 1px solid #ccc; background: #f8f9fa; } </style> </head> <body> <canvas id="board" width="640" height="360"></canvas> <script> // Step 1: Grab the <canvas> element const canvas = document.getElementById('board'); // Step 2: Get the 2D drawing context (your paintbrush) const ctx = canvas.getContext('2d'); // Step 3: Set colors / styles ctx.fillStyle = '#4CAF50'; // green fill ctx.strokeStyle = '#2E7D32'; // darker green stroke ctx.lineWidth = 6; // Step 4: Draw! ctx.fillRect(80, 80, 200, 120); // filled rectangle ctx.strokeRect(340, 80, 200, 120); // outlined rectangle // Text ctx.font = 'bold 48px Arial'; ctx.fillStyle = '#2196F3'; ctx.textAlign = 'center'; ctx.fillText('Hello Canvas!', 320, 280); </script> </body> </html> |
Key sentences to remember forever:
- getContext(‘2d’) is the only method you need 99% of the time
- All drawing happens through the ctx object
- State is sticky — fillStyle stays red until you change it again
2. Understanding coordinate system (very important)
- (0,0) is top-left corner
- x increases → right
- y increases → down (opposite of math graphs)
Quick test — where will this draw?
|
0 1 2 3 4 5 6 7 |
ctx.fillRect(0, 0, 100, 100); // top-left square ctx.fillRect(540, 260, 100, 100); // bottom-right square |
3. Paths – the most important concept after context
Almost everything interesting in Canvas is a path.
Basic pattern you will write 1000 times:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
ctx.beginPath(); // ← very important – forget it and paths connect unexpectedly ctx.moveTo(100, 100); // pen up + jump to start point ctx.lineTo(300, 50); ctx.lineTo(400, 180); ctx.closePath(); // optional – connects back to start ctx.strokeStyle = '#673AB7'; ctx.lineWidth = 10; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.stroke(); // ← actually draw the outline // or fill it ctx.fillStyle = 'rgba(103,58,183,0.3)'; ctx.fill(); |
4. Circles, arcs, pies
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
ctx.beginPath(); ctx.arc( 320, 180, // center x,y 70, // radius 0, // start angle (0 = right) Math.PI * 1.8, // end angle (Math.PI*2 = full circle) false // counterclockwise? (almost always false) ); ctx.fillStyle = '#FF9800'; ctx.fill(); ctx.strokeStyle = '#EF6C00'; ctx.lineWidth = 14; ctx.stroke(); |
Quick angles reference (radians)
- 0 = right (3 o’clock)
- Math.PI/2 = down (6 o’clock)
- Math.PI = left (9 o’clock)
- Math.PI*2 = full circle (back to start)
5. Animation – the 60 fps heartbeat pattern
This is the structure every Canvas animation/game uses:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
const canvas = document.getElementById('c'); const ctx = canvas.getContext('2d'); let x = 100; let y = 100; let vx = 3.7; // velocity x let vy = 2.1; function animate() { // 1. Clear previous frame ctx.clearRect(0, 0, canvas.width, canvas.height); // 2. Update logic x += vx; y += vy; // Bounce on edges if (x < 30 || x > canvas.width - 30) vx = -vx; if (y < 30 || y > canvas.height - 30) vy = -vy; // 3. Draw ctx.beginPath(); ctx.arc(x, y, 30, 0, Math.PI*2); ctx.fillStyle = '#2196F3'; ctx.fill(); // 4. Ask browser to call us again (~16 ms later = ~60 fps) requestAnimationFrame(animate); } // Start the loop requestAnimationFrame(animate); |
Why requestAnimationFrame and not setInterval?
- Browser-optimized (syncs with display refresh rate)
- Pauses automatically when tab is inactive
- Better battery life
- Smoother motion
6. Quick reference table – 80/20 most used commands
| Goal | Code example |
|---|---|
| Clear whole canvas | ctx.clearRect(0,0,canvas.width,canvas.height) |
| Draw filled rectangle | ctx.fillRect(x,y,w,h) |
| Draw outline rectangle | ctx.strokeRect(x,y,w,h) |
| Draw circle | ctx.arc(cx,cy,r,0,Math.PI*2); ctx.fill() |
| Draw line | ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke() |
| Set color | ctx.fillStyle = ‘#FF5722’ or ‘rgba(255,87,34,0.7)’ |
| Line thickness & style | ctx.lineWidth = 6; ctx.lineCap = ’round’ |
| Text | ctx.font = ‘bold 40px Arial’; ctx.fillText(‘Hi’,x,y) |
| Save / restore state | ctx.save(); … change stuff … ctx.restore(); |
| Rotate around point | ctx.translate(cx,cy); ctx.rotate(angle); ctx.translate(-cx,-cy); |
| Scale | ctx.scale(2,2) |
Your first 3 homework tasks (do them tonight)
Task 1 – Smiley face Draw a yellow circle face + two black eyes + red smiling arc mouth
Task 2 – Bouncing ball Use the animation loop example above — make the ball bounce off all four walls
Task 3 – Colorful trail Modify the bouncing ball so it leaves a fading trail (hint: don’t clear the whole canvas — clear with semi-transparent black rectangle)
Paste any of them here when you’re done — I’ll give detailed feedback like we’re pair-programming together.
Which part feels most confusing right now?
- The stateful painter concept?
- Paths vs simple shapes?
- Animation loop & requestAnimationFrame?
- How Canvas differs from SVG?
- Something else?
Tell me honestly — we’ll slow down and fix exactly the part that’s fuzzy for you. You’re doing great — Canvas is tricky at first, but once it clicks it’s incredibly rewarding! 🚀
