Week 11: Canvas Games & APIs with fetch()
To Do This Week
Explore Canvas game techniques and APIs with fetch(). Add to your running list of combination ideas for the Front-End Module Projects. Each project combines at least two front-end modules:
- HTML5 Audio or Video
- Canvas drawing or animation (or SVG)
- p5.js
- An API using
fetch() - Canvas game techniques
Use AI freely to research and test ideas. If you use AI to build logic steps and syntax, use JS Mentor, and document what it contributed and how you changed and extended it.
Monday: Canvas Games
A game is an animation loop plus state (score, lives, level, game over) plus input (keys, mouse, touch). Each frame the loop clears the canvas, reads input, updates every object, checks for collisions, and redraws.
HTML5 Games
Explore the W3Schools HTML5 Games Demo to see how JavaScript builds a game on the Canvas element.
Here is the example refactored for ES6: Dodging Obstacles Game. Look at how objects are generated and then animated with speed and gravity properties. Experiment with values.
New Syntax: Classes
A class is a blueprint. Write it once, then make as many objects from it as you need: one player, fifty obstacles, a hundred falling stars.
class Ball {
constructor(x, y, speed) { // runs when a new Ball is made
this.x = x; // "this" = the ball being made
this.y = y;
this.speed = speed;
this.radius = 15;
}
update() { // a method: what the ball does each frame
this.y += this.speed;
}
draw() { // a method: how the ball looks
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
ctx.fill();
}
}
const balls = []; // many objects in an array
balls.push(new Ball(100, 0, 3));
balls.push(new Ball(250, 0, 5));
Arrow Functions (=>)
An arrow function is a shorter way to write a function. If you see =>, it means “this is a function.”
// Arrow function
balls.forEach(ball => {
ball.update();
ball.draw();
});
// Same thing as a regular function
balls.forEach(function(ball) {
ball.update();
ball.draw();
});
Keyboard Input
Store which keys are held down as booleans, then check them inside the game loop. This gives smooth movement instead of one jump per key press.
const keys = {};
document.addEventListener('keydown', e => keys[e.key] = true);
document.addEventListener('keyup', e => keys[e.key] = false);
// inside the game loop
if (keys['ArrowLeft']) player.x -= player.speed;
if (keys['ArrowRight']) player.x += player.speed;
Collision Detection (Rectangles)
function hits(a, b) {
return a.x < b.x + b.width &&
a.x + a.width > b.x &&
a.y < b.y + b.height &&
a.y + a.height > b.y;
}
if (hits(player, enemy)) {
gameOver = true;
}
The Game Loop
function updateGame() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // 1. clear
player.update(); // 2. update
balls.forEach(ball => ball.update());
balls.forEach(ball => { // 3. check collisions
if (hits(player, ball)) score++;
});
player.draw(); // 4. draw
balls.forEach(ball => ball.draw());
ctx.fillText('Score: ' + score, 20, 30);
if (!gameOver) requestAnimationFrame(updateGame); // 5. repeat
}
Adding Images and Sound Effects
To add images, load the image into an Image() object, then draw it with drawImage() in place of a shape.
const playerImg = new Image();
playerImg.src = 'player.png';
// inside the player's draw() method
ctx.drawImage(playerImg, this.x, this.y, this.width, this.height);
To add sound effects, load the audio file into an Audio() object and call play() when something happens in the game.
const shootSound = new Audio('shoot.wav');
// when the player shoots
shootSound.currentTime = 0; // rewind so it can retrigger quickly
shootSound.play();
- Images load asynchronously. If a sprite doesn’t appear on the first frame, start the game after it loads:
playerImg.onload = () => startGame(); - Browsers block sound until the user interacts, so a Start button or title screen is a good place to begin music.
- Keep assets in an
images/andsounds/folder and use relative paths.
The game with images | Download ZIP
Demos
- Dodging Obstacles (ES6) — objects, speed, and gravity
- Falling Balls — keyboard input and collecting
- Game with Images — sprites and sound
- Pong | Asteroids — classic games refactored to ES6 classes
Writing Logic Steps First: Pong
Before coding a game, describe it in plain language. Here is Pong:
- Set up the canvas: Get the canvas element and its drawing context so we can draw paddles and the ball.
- Create a
Paddleclass: Each paddle has a position (x, y), size (width, height), and speed. It responds to player input (W/S, arrow keys) and draws itself each frame. - Create a
Ballclass: The ball has a position, size, and speed in both X and Y directions. It moves, bounces, detects paddle collisions, and resets after a score. - Track game state: Keep score, listen for key presses, and use booleans to store which keys are held down.
- Game loop (
updateGame): Clear the canvas, update positions, check for collisions, draw everything, and userequestAnimationFrame()to repeat.
Asteroids Logic Steps
- Set up the canvas: Same as Pong.
- Create a
Shipclass: Position, direction, and thrust; moves with physics, rotates, shoots, and wraps around the screen. - Create a
Bulletclass: Starts at the ship’s position, moves in its direction, and disappears after a while. - Create an
Asteroidclass: Random positions and velocities; moves, wraps around, and detects bullet hits. - Create a
Gameclass: Manages the ship, asteroids, and input; runs the update/draw loop.
Previous Student Canvas Games
- Escape the Room
- Welcome to Greenhedge
- Game: Inventory
- Knight Runner
- Undead Outpost
- Cowardly Blocks
- Welcome to Kiwi’s Garden!
- Dueling Tanks
- Star Adventures
- Color Mixing Game
Knight Runner: How a Larger Game Is Organized
Larger games split each class into its own file. Look at how Knight Runner is organized:
- main.js — sets up the game and runs the loop
- player.js and playerStates.js — the player and its states (running, jumping, rolling)
- input.js — keyboard handling
- background.js — layered scrolling background
- enemies.js — enemy classes
- UI.js — score and on-screen text
Its assets: UI elements from OwlishMedia, background layers from Edermunizz, and sprites from Dumbmanex, Craftpix, OpenGameArt, and Freepik.
HTML5 Game Elements
- Web Storage — save a high score with
localStorage - Drag and Drop
- JavaScript Progress Bar
- Custom Range Sliders
Game Resources
- Franks Laboratory — Canvas game tutorials
- html5-games-cheatsheet.pdf
Game Assets + AI Tools
-
Sprites, Backgrounds, Tiles
- Ludo – AI sprite and spritesheet generator
- OpenGameArt – free sprites, textures, music, and sound effects (Creative Commons)
- itch.io Game Assets – free pixel art packs, characters, and UI kits
- CraftPix – free game kits, sprites, backgrounds, GUI elements
- GameArt2D – sprite sheets, tilesets, and backgrounds
-
Sound Effects & Music
- Freesound – user-uploaded sound effects (Creative Commons)
- itch.io Audio Packs – free SFX and music for games
-
AI Image, Sound, and Voice Tools
- ChatGPT Image, Midjourney, Leonardo AI – characters, objects, backgrounds, concept art
- ElevenLabs, PlayHT – voices and narration
- Suno – music tracks and loops
Check the license for every asset you use and credit it in your project.
Monday In-Class Sandbox
Start from Falling Balls or Dodging Obstacles and make it your own.
- Play it, then experiment with values: speed, gravity, spawn rate, player size and controls.
- Write three to five numbered logic steps for one real change to how the game plays (a new rule, a new object, a win condition). Use JS Mentor to work out the syntax.
- Replace at least one shape with an image using
drawImage(). - Add a sound effect for one game event: a catch, a hit, or game over.
What would I combine this with? Add one sentence to your list.
Wednesday: APIs with fetch()
An API (Application Programming Interface) lets your page request data from another service: weather, art collections, space images, poems. The data usually comes back as JSON, which JavaScript reads as an object. Live data can then drive what your page shows, how an animation moves, or how a game behaves.
Server Requests
- Old way: Ajax — asynchronous JavaScript and XML, used for passing data (GET or POST) without refreshing the page. XML — extensible markup language, once used for storing and exchanging data.
- New way (with ES6): the JavaScript Fetch API along with JSON — JavaScript Object Notation, a format for storing and exchanging data.
The Fetch API is a built-in browser feature: a set of methods that make network requests like GET (grab data), POST (send data), and PUT / DELETE (update or remove data). For most front-end projects you only need GET.
New Syntax: fetch()
const apiKey = 'YOUR_API_KEY';
async function getWeather(city) {
const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=imperial&appid=${apiKey}`;
try {
const response = await fetch(url); // 1. send the request, wait for a reply
if (!response.ok) { // 2. check it worked (404 = city not found)
throw new Error('City not found');
}
const data = await response.json(); // 3. turn the reply into a JS object
showWeather(data); // 4. use the data
} catch (error) {
message.textContent = error.message; // 5. tell the user what went wrong
}
}
asyncmarks a function that waits for something.awaitpauses inside it until the request comes back, so the rest of the page keeps working.try/catchhandles errors: a misspelled city, no network, or a bad API key.- Template literals (backticks with
${ }) build the request URL from variables. - You may also see the older
.then()style:fetch(url).then(res => res.json()).then(data => showWeather(data));It does the same thing.
JSON Methods
- response.json() — A fetch shortcut that reads the response and parses it into a JS object in one step.
- JSON.parse() — Converts a JSON string into a JS object. Used when you already have a JSON string in hand.
- JSON.stringify() — Converts a JS object into a JSON string. Used when sending data to a server or saving to
localStorage.
Reading Nested JSON
Use dot notation to reach into the object, and square brackets for arrays. Open the JSON Weather Data and trace each path:
data.name // "Vancouver"
data.main.temp // 54.3
data.main.humidity // 81
data.wind.speed // 6.9
data.clouds.all // 75 (cloud cover %)
data.weather[0].main // "Rain"
data.weather[0].description // "light rain"
data.sys.sunrise / data.sys.sunset / data.dt // times, for day vs. night
Use includes() to search a description for a word:
if (data.weather[0].description.includes('clouds')) {
// Do something
}
Demo: Weather App
Use the OpenWeather API to get current weather by city with fetch().
Getting an API Key
- Go to the sign-up page for the free version.
- Your key will be emailed to you. It can take a little while to activate.
- Replace the placeholder key in the template with your own.
For a US city with a state, use the format Vancouver,WA,US.
Weather App Resources
- OpenWeather API: Current Weather Data
- JSON Weather Data — an example response
- Weather Conditions — a list of all weather descriptions
- JSON Prettify — make a raw response readable
Other APIs to Explore
- Open-Meteo — weather and forecasts, no key needed
- Art Institute of Chicago API — artworks and images, no key needed
- NASA APIs — Astronomy Picture of the Day and more (free key)
- PoetryDB — poems by author and title, no key needed
Wednesday In-Class Sandbox: Weather + Canvas Animation
Turn live weather into motion. Start from a weather app template and add a canvas that animates according to the data.
- Get the template working with your own API key. Test a few cities.
- Pick two or three data points to drive the animation.
- Add a canvas and an animation loop. You can start from a rain or snow animation demo, or a p5.js sketch.
- Connect each data point to something visual. Ideas:
data.wind.speed→ how fast or sideways particles movedata.clouds.all→ how many clouds, or how gray the sky isdata.main.temp→ color palette, warm to cooldata.weather[0].main→ which animation runs: rain, snow, sun, fogdata.dtcompared to sunrise and sunset → day or night sky
- Add a loading message and an error message for a city that isn’t found.
// Example: wind speed (0–30 mph) controls drift, temperature controls color
let drift = (data.wind.speed / 30) * 5; // 0 to 5 pixels per frame
let warm = Math.min(Math.max((data.main.temp - 20) / 80, 0), 1); // 0 = cold, 1 = hot
ctx.fillStyle = `rgb(${warm * 255}, 120, ${(1 - warm) * 255})`;
Think about mood, not just accuracy. A weather app can be calm, eerie, playful, or poetic. Other directions: a game that gets harder in bad weather, a soundscape that shifts with conditions, or another API from the list above.
What would I combine this with? Add one sentence to your list.