Session 2: Game Time - Click Speed and Gem Catcher
Goal: Set up VS Code and GitHub, then complete two games by adding the key logic yourself Prerequisites: Session 1 (HTML, CSS, JavaScript basics)
What You Will Build Today
You will start with starter code that has the HTML, CSS, and structure already built. Your job is to fill in the game logic — the JavaScript that makes the games actually work.
Game 1 - Click Speed Challenge: Race against a 10-second timer to click as many times as possible. You will add: the click handler, start game setup, and end game logic.
Game 2 - Gem Catcher: Catch colorful falling gems by moving a basket with your mouse or keyboard. You will add: collision detection, scoring, lives tracking, and gem spawning — building on the same patterns from Game 1.
Part 1: Set Up Your Developer Environment
In Session 1 we used CodePen to write code in the browser. Now we are switching to VS Code — a real code editor that professional developers use. This gives us files on our computer, Git version control, and the ability to build bigger projects.
Open VS Code and Install Live Server
- Open VS Code
- Install the Live Server extension:
- Click the Extensions icon in the left sidebar (or press
Cmd+Shift+X) - Search for “Live Server” by Ritwick Dey (extension ID:
ritwickdey.LiveServer) - Click Install
- Click the Extensions icon in the left sidebar (or press
Accept Your GitHub Assignment
- Click this link to create your own copy of the starter code: Accept the Assignment
- Sign in to GitHub if prompted, then click Accept this assignment
- Wait a few seconds — GitHub will create a repository for you with the starter code
- Copy your repository URL (it will look like
https://github.com/...)
Clone the Starter Code
- Open the VS Code terminal: Terminal > New Terminal (or press
Ctrl+`) - Clone your new repository:
git clone <YOUR-REPOSITORY-URL>
- Open the cloned folder in VS Code: File > Open Folder and select the folder that was created
- You should see these files in VS Code:
click-game.html— Click Speed Challenge (with TODOs)gem-catcher.html— Gem Catcher (with TODOs)README.md— Instructions
Preview the Starter Code
- Right-click
click-game.htmlin the file explorer - Select Open with Live Server
- You should see the game layout — but clicking does nothing yet! That is what you will fix.
Part 2: Click Speed Challenge
Open click-game.html in VS Code. The HTML structure, CSS styling, element selectors, and game state variables are already written for you. Look for the // TODO comments — those are the parts you need to complete.
Understanding What is Already There
Scroll through the code and notice:
| Already Built | What It Does |
|---|---|
| HTML structure | Buttons, score display, timer display |
| CSS styling | Colors, layout, animations |
document.getElementById() |
Grabs each element so JavaScript can control it |
| Game state variables | score, timeLeft, highScore, gameRunning |
updateTimer() function |
Counts down every 0.1 seconds |
| Start button event listener | Calls startGame() when clicked |
TODO 1: Handle the Click Button
Find this section in the code:
clickButton.addEventListener('click', function() {
// TODO 1: Handle the click!
Your task: When the game is running, add 1 to the score and update the display.
Write this code:
if (gameRunning) {
score++;
scoreDisplay.textContent = score;
}
What you just learned:
addEventListener('click', ...)runs code when a button is clickedscore++is shorthand forscore = score + 1.textContentchanges what text appears on screen
TODO 2: Start the Game
Find:
function startGame() {
// TODO 2: Set up the game to start!
Your task: Reset everything and start the timer.
Write this code:
score = 0;
timeLeft = 10;
gameRunning = true;
messageDisplay.textContent = '';
scoreDisplay.textContent = score;
timerDisplay.textContent = timeLeft.toFixed(1);
clickButton.disabled = false;
clickButton.textContent = 'CLICK ME!';
startButton.textContent = 'Game Running...';
startButton.disabled = true;
timerInterval = setInterval(updateTimer, 100);
What you just learned:
- Resetting variables to their starting values
.toFixed(1)shows one decimal place (10.0 instead of 10).disabled = falsemakes a button clickable againsetInterval(fn, 100)calls a function every 100 milliseconds (0.1 seconds)
TODO 3: End the Game
Find:
function endGame() {
// TODO 3: End the game!
Your task: Stop the timer, disable the button, and check for a high score.
Write this code:
gameRunning = false;
clearInterval(timerInterval);
clickButton.disabled = true;
clickButton.textContent = "Time's Up!";
startButton.disabled = false;
startButton.textContent = 'PLAY AGAIN';
if (score > highScore) {
highScore = score;
highScoreDisplay.textContent = highScore;
messageDisplay.textContent = 'NEW HIGH SCORE!';
} else {
messageDisplay.textContent = 'Game Over! Your score: ' + score;
}
timerDisplay.textContent = '0.0';
What you just learned:
clearInterval()stops a repeating timerif/elsemakes decisions based on conditions- String concatenation with
+combines text and numbers
Test It!
Save the file and check your browser. The game should now work:
- Click START → timer counts down
- Click the big button → score goes up
- Time runs out → shows your score and tracks high score
Quick Customizations
Pick one:
- Change
timeLeft = 10to5for hard mode - Change the button gradient colors in the CSS
- Add
const cps = (score / 10).toFixed(1);in endGame and display clicks-per-second
Save Your Progress
git add click-game.html
git commit -m "Complete click speed challenge"
Part 3: Gem Catcher - Expanding Your Skills
Now open gem-catcher.html. This game uses the exact same patterns you just learned — score tracking, conditional logic, game state — but adds canvas animation.
What is Canvas?
The <canvas> element is like a blank drawing board. JavaScript paints shapes and animations on it frame by frame, just like a flipbook.
What is Already Built
Take a look through the code:
| Already Built | What It Does |
|---|---|
| Canvas setup | getContext('2d') creates the drawing tool |
| Basket object | Position, size, speed, color stored in one object |
createGem() |
Makes a new gem with random position and color |
| Drawing functions | drawBasket(), drawGem(), clearCanvas() |
| Mouse + keyboard controls | Move the basket left and right |
startGame() / endGame() |
Reset and end the game |
| Game loop structure | The gameLoop() runs 60 times per second |
The game loop already moves gems downward and draws them. But gems pass right through the basket! You need to add the logic that makes catching and missing actually work.
TODO 1: Collision Detection
Find:
function checkCollision(gem, basket) {
// TODO 1: Check if a gem is touching the basket!
Your task: Two rectangles overlap when all four of these conditions are true at the same time. Return true when they overlap.
Replace return false; with:
return gem.x < basket.x + basket.width &&
gem.x + gem.width > basket.x &&
gem.y < basket.y + basket.height &&
gem.y + gem.height > basket.y;
What you just learned:
- Collision detection = checking if two rectangles overlap
&&means AND — all conditions must be true- This is the same
iflogic from the Click Speed game, just with more conditions combined
TODO 2: Score a Caught Gem
Find:
// TODO 2: Update the score when a gem is caught!
Your task: Just like in the Click Speed game — add 1 to score and update the display. Then remove the gem.
Write this code:
score++;
scoreDisplay.textContent = score;
gems.splice(i, 1);
continue;
Connection to Game 1: This is the exact same score++ and scoreDisplay.textContent = score pattern! The new part is splice(i, 1) which removes the caught gem from the array.
TODO 3: Handle a Missed Gem
Find:
// TODO 3: Handle a missed gem!
Your task: When a gem falls off screen, lose a life. If lives hit zero, end the game.
Write this code:
lives--;
livesDisplay.textContent = lives;
gems.splice(i, 1);
if (lives <= 0) {
endGame();
return;
}
continue;
Connection to Game 1: In the Click Speed game, the game ended when time ran out. Here it ends when lives run out — same pattern, different trigger.
TODO 4: Spawn New Gems
Find:
// TODO 4: Spawn new gems randomly!
Your task: Each frame, there is a small random chance a new gem appears.
Write this code:
if (Math.random() < 0.02) {
gems.push(createGem());
}
What you just learned:
Math.random()returns a number between 0 and 1< 0.02means roughly 2% chance each frame ≈ 1-2 new gems per second.push()adds an item to an array
Test It!
Save and check your browser:
- Gems should fall from the top
- Moving the basket under a gem catches it (score goes up)
- Missing a gem costs a life
- Game ends when lives reach 0
Key Concepts Comparison
| Concept | Click Speed Game | Gem Catcher |
|---|---|---|
| Score tracking | score++ on click |
score++ on catch |
| Game end condition | Time runs out | Lives run out |
| User input | Button click | Mouse / keyboard movement |
| Display update | textContent |
textContent + canvas redraw |
| Timing | setInterval (fixed) |
requestAnimationFrame (smooth) |
Your Turn - Customize
Pick one or more:
- Change gem colors: Edit the
colorsarray increateGem() - Adjust difficulty: Change
0.02(spawn rate) or gemspeedvalues - More lives: Change
lives = 3tolives = 5instartGame() - Wider basket: Change
basket.widthfrom100to150 - Golden gems (challenge): Add rare gems worth 5 points:
// In createGem(), before the return statement:
const isGolden = Math.random() < 0.1; // 10% chance
// Change the return to include:
return {
x: Math.random() * (canvas.width - 30),
y: -30,
width: 30,
height: 30,
speed: 2 + Math.random() * 2,
color: isGolden ? '#FFD700' : randomColor,
points: isGolden ? 5 : 1,
caught: false
};
// Then in TODO 2, change: score++ to: score += gem.points;
Save and Push to GitHub
git add .
git commit -m "Complete click speed and gem catcher games"
git push origin main
What You Learned Today
Developer Tools:
- VS Code with Live Server for instant preview
- Git for saving progress and pushing to GitHub
JavaScript Patterns (used in BOTH games):
- Event listeners — responding to clicks, mouse moves, and key presses
- Game state variables — tracking score, time, lives
- Conditional logic —
if/elsefor decisions (high score check, collision, game over) - DOM updates — changing what players see with
.textContent
New in Gem Catcher (building on Click Speed):
- HTML Canvas — drawing graphics with JavaScript
- Animation loops —
requestAnimationFrame()for smooth 60fps movement - Collision detection — checking if rectangles overlap
- Arrays — managing multiple gems with
push()andsplice()
Homework (Optional)
- Click Game: Add difficulty levels (Easy: 15s, Medium: 10s, Hard: 5s)
- Click Game: Save high score with
localStorageso it persists after closing - Gem Catcher: Add “bomb” objects that cost a life if caught
- Gem Catcher: Make gems fall faster as your score increases
- Both: Change the visual theme (colors, gradients, title text)
Common Issues
Problem: “Page looks right but clicking does nothing” Solution: Check that your TODO code is inside the correct function, not outside the curly braces
Problem: “Timer does not count down”
Solution: Make sure setInterval(updateTimer, 100) is in your startGame() function
Problem: “Gems pass through the basket”
Solution: Check your collision detection — all four && conditions must be correct
Problem: “Score does not go up when catching gems”
Solution: Make sure you have both score++ and scoreDisplay.textContent = score
Problem: “Gems never appear”
Solution: Check TODO 4 — make sure gems.push(createGem()) is inside the if (Math.random() < 0.02) block
Problem: “Git push failed”
Solution: git remote -v — if empty, add your remote: git remote add origin YOUR-URL
Resources
← Session 1 | Back to GameCraft Home | Next: Session 3 - React →