Canvas Foundation
Your first surface — the HTML canvas element
Chapter goal
Create a full document with a canvas, grab a 2D drawing context, and paint a solid world so the browser becomes your game screen.
How to do it
- 1
Scaffold a page
A game engine in pure HTML starts as a normal webpage: doctype, head, body. Inside the body you place a single <canvas> — the pixel surface everything draws onto.
- 2
Get the 2D context
Call canvas.getContext('2d') once. That context object (ctx) is the API for clearing pixels, drawing shapes, text, and later images.
- 3
Paint the world
fillStyle sets the color; fillRect(x, y, w, h) stamps a rectangle. Coordinates start at the top-left (0,0) and increase right and down.
Live lab
Solution code updates with sliders. Tinker is your sandbox. Play runs whichever document you launch.
Live settings
Every slider injects into the engine constants for this chapter.
The chapter engine script is prewritten below. Type it line by line — each line explains why it belongs there. Matching a line advances automatically; Enter re-checks if you are stuck.
1(function () {2 "use strict";3 // Single boot — if this document is re-parsed, abandon prior work.4 if (window.__engineBooted) return;5 window.__engineBooted = true;6 let alive = true;7 window.addEventListener("pagehide", function () { alive = false; }, { once: true });8 const raf = window.requestAnimationFrame.bind(window);9 window.requestAnimationFrame = function (cb) {10 return raf(function (ts) {11 if (!alive) return;12 try { cb(ts); } catch (err) { console.error(err); alive = false; }13 });14 };1516const canvas = document.getElementById('c');17const ctx = canvas.getContext('2d');18const W = canvas.width, H = canvas.height;1920const BG_R = 11;21const BG_G = 16;22const BG_B = 24;23const GRID = 32;24const ACCENT = 55 / 100;2526function draw() {27 ctx.fillStyle = `rgb(${BG_R},${BG_G},${BG_B})`;28 ctx.fillRect(0, 0, W, H);2930 ctx.strokeStyle = `rgba(94,234,212,${0.08 + ACCENT * 0.12})`;31 ctx.lineWidth = 1;32 for (let x = 0; x <= W; x += GRID) {33 ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, H); ctx.stroke();34 }35 for (let y = 0; y <= H; y += GRID) {36 ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(W, y); ctx.stroke();37 }3839 // Horizon wash40 const g = ctx.createLinearGradient(0, H * 0.4, 0, H);41 g.addColorStop(0, 'transparent');42 g.addColorStop(1, `rgba(94,234,212,${0.05 + ACCENT * 0.15})`);43 ctx.fillStyle = g;44 ctx.fillRect(0, 0, W, H);4546 // Title plate47 ctx.fillStyle = `rgba(94,234,212,${0.12 + ACCENT * 0.25})`;48 roundRect(ctx, W/2 - 140, H/2 - 36, 280, 72, 14);49 ctx.fill();50 ctx.strokeStyle = `rgba(94,234,212,${0.35 + ACCENT * 0.4})`;51 ctx.stroke();5253 ctx.fillStyle = '#e8edf5';54 ctx.font = '600 18px system-ui,sans-serif';55 ctx.textAlign = 'center';56 ctx.fillText('Engine Surface Online', W/2, H/2 - 4);57 ctx.fillStyle = '#8b97ab';58 ctx.font = '12px ui-monospace,monospace';59 ctx.fillText(W + '×' + H + ' canvas · 2D context', W/2, H/2 + 18);6061 document.getElementById('hud').textContent = 'Chapter 1 · static frame';62}6364function roundRect(ctx, x, y, w, h, r) {65 ctx.beginPath();66 ctx.moveTo(x+r, y);67 ctx.arcTo(x+w, y, x+w, y+h, r);68 ctx.arcTo(x+w, y+h, x, y+h, r);69 ctx.arcTo(x, y+h, x, y, r);70 ctx.arcTo(x, y, x+w, y, r);71 ctx.closePath();72}7374draw();7576})();
Static scene — use sliders to restyle the canvas world. · Sliders update the play window after a short pause.