What they learn:
A webpage can contain a <canvas> — a digital drawing board.
JavaScript can draw images onto it.
File inputs let you pick an image from your computer.
How to explain it:
“Think of the canvas like a blank sheet of paper. JavaScript is your pen. First we need to load a picture onto the paper.”
Code they write (simple, readable):
HTML
<input type="file" id="imgInput">
<canvas id="canvas"></canvas>
JS
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let img = new Image();
document.getElementById("imgInput").onchange = e => {
img.src = URL.createObjectURL(e.target.files[0]);
};
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
};
Quick check:
They upload an image and it appears on the page.
What they learn:
Big images break the layout.
We can scale them down while keeping the same shape.
How to explain it:
“Imagine shrinking a photo to fit in a frame. We keep the same shape, just smaller.”
Code they add:
JS
img.onload = () => {
const maxWidth = 800;
const scale = img.width > maxWidth ? maxWidth / img.width : 1;
canvas.width = img.width * scale;
canvas.height = img.height * scale;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
};
Quick check:
Huge photos now shrink to a sensible size.
What they learn:
How to draw text on a canvas
How to set font, colour, outline
Why memes use “Impact” style text
How to explain it:
“We’re writing on top of the picture. The outline makes the text readable no matter what colour the background is.”
HTML they add:
<input id="topText" placeholder="Top text">
<input id="bottomText" placeholder="Bottom text">
<button onclick="drawMeme()">Update Meme</button>
JS they add:
function drawMeme() {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
ctx.font = "40px Impact";
ctx.fillStyle = "white";
ctx.strokeStyle = "black";
ctx.lineWidth = 4;
ctx.textAlign = "center";
ctx.fillText(topText.value, canvas.width / 2, 50);
ctx.strokeText(topText.value, canvas.width / 2, 50);
ctx.fillText(bottomText.value, canvas.width / 2, canvas.height - 20);
ctx.strokeText(bottomText.value, canvas.width / 2, canvas.height - 20);
}
Quick check:
Typing text and clicking “Update Meme” shows the text on the image.
What they learn:
Sliders
Using variables to control drawing
Re‑drawing the canvas when something changes
How to explain it:
“Instead of hard‑coding the text size, we let the user choose it.”
HTML they add:
<label>Text size: <input type="range" id="textSize" min="20" max="80" value="40"></label>
JS they add:
function drawMeme() {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
const size = textSize.value;
ctx.font = `${size}px Impact`;
ctx.fillStyle = "white";
ctx.strokeStyle = "black";
ctx.lineWidth = size / 10;
ctx.textAlign = "center";
ctx.fillText(topText.value, canvas.width / 2, size);
ctx.strokeText(topText.value, canvas.width / 2, size);
ctx.fillText(bottomText.value, canvas.width / 2, canvas.height - size / 2);
ctx.strokeText(bottomText.value, canvas.width / 2, canvas.height - size / 2);
}
Quick check:
Dragging the slider makes the text bigger or smaller.
What they learn:
More sliders
Mapping slider values to canvas coordinates
How to explain it:
“We’re letting you move the text up and down the picture.”
HTML they add:
<label>Top text position: <input type="range" id="topPos" min="0" max="100" value="10"></label>
<label>Bottom text position: <input type="range" id="bottomPos" min="0" max="100" value="90"></label>
JS they add:
const topY = (topPos.value / 100) * canvas.height;
const bottomY = (bottomPos.value / 100) * canvas.height;
Then replace the text positions with:
ctx.fillText(topText.value, canvas.width / 2, topY);
ctx.strokeText(topText.value, canvas.width / 2, topY);
ctx.fillText(bottomText.value, canvas.width / 2, bottomY);
ctx.strokeText(bottomText.value, canvas.width / 2, bottomY);
Quick check:
Moving sliders moves the text.
What they learn:
How to export the canvas as an image
How to trigger a download
HTML they add:
<button onclick="downloadMeme()">Download Meme</button>
JS they add:
function downloadMeme() {
const link = document.createElement("a");
link.download = "meme.png";
link.href = canvas.toDataURL();
link.click();
}
Quick check:
Clicking “Download Meme” saves a PNG.
// Redraw on input
topText.oninput = drawMeme;
bottomText.oninput = drawMeme;
textSize.oninput = drawMeme;
topPos.oninput = drawMeme;
bottomPos.oninput = drawMeme;
Control maximum page width (CSS)
Change font
Change text colour