Make a Meme Generator - Instructions

🧱 Stage 1 — The Canvas + Image Upload (10 minutes)

What they learn:

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.


🧱 Stage 2 — Auto‑Resize Large Images (10 minutes)

What they learn:

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.


🧱 Stage 3 — Add Top & Bottom Text (15 minutes)

What they learn:

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.


🧱 Stage 4 — Adjustable Text Size (10 minutes)

What they learn:

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.


🧱 Stage 5 — Adjustable Text Position (10 minutes)

What they learn:

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.


🧱 Stage 6 — Download Button (5 minutes)

What they learn:

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.


🎉 Optional Enhancements (if time allows)

Meme Dynamically Updates when Scrolling

// Redraw on input
topText.oninput  =  drawMeme;
bottomText.oninput  =  drawMeme;
textSize.oninput  =  drawMeme;
topPos.oninput  =  drawMeme;
bottomPos.oninput  =  drawMeme;

Other