Skip to content

Stage 1 — HTML Structure and Canvas Setup

In Stage 1 you write the HTML that frames the entire game and the opening lines of JavaScript that give the game a name and a home. By the end of this stage you will have a dark canvas visible in the browser — empty, but ready.


  • index.html — the complete HTML structure for the game
  • The opening stub of pop.js — the POP namespace object with a wired-up init() method

Checkpoint: open index.html in a browser — you should see a dark blue-to-purple gradient canvas with a Start screen overlay.


Create a project folder and add three empty files:

bubble-pop/
├── index.html
├── style.css
└── pop.js

The HTML has four jobs:

  1. Set up the document and load the stylesheet and script
  2. Provide the <canvas> where all game graphics are drawn
  3. Add a HUD (heads-up display) showing score, level, and lives
  4. Add two overlay screens — start and game over — that sit on top of the canvas

Open index.html and write:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Bubble Pop</title>
<link rel="icon" href="favicon.svg" type="image/svg+xml" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="game-container">
<canvas id="game-canvas"></canvas>
<div id="hud">
<span id="score-display">Score: 0</span>
<span id="level-display">Level: 1</span>
<span id="lives-display">Lives: 3</span>
</div>
<div id="start-screen" class="screen">
<h1>Bubble Pop</h1>
<p id="high-score-display">Best: 0</p>
<p class="instructions">Click or tap bubbles before they escape!</p>
<button id="start-btn" type="button">Play</button>
</div>
<div id="gameover-screen" class="screen hidden">
<h2>Game Over</h2>
<p id="final-score">Score: 0</p>
<p id="new-high-score" class="hidden">New High Score!</p>
<button id="restart-btn" type="button">Play Again</button>
</div>
</div>
<script src="pop.js"></script>
</body>
</html>
  • <canvas id="game-canvas"> — the rendering surface. The JS will set its pixel dimensions; CSS controls how it is sized on screen.
  • #hud — sits on top of the canvas via absolute positioning. Updated by JS every time the score or lives change.
  • #start-screen / #gameover-screen — both have class screen. The game-over screen also starts with class hidden. The JS adds and removes hidden to switch between them.
  • <script> at the bottom — the script loads after the DOM is fully parsed, so document.getElementById calls in JS will find the elements immediately.

Before writing any game logic, establish the POP namespace object. A namespace object keeps all game variables and functions in one place and avoids polluting the global scope.

Open pop.js and write:

const POP = {
// Config will go here in Stage 3
config: {},
// State
state: 'start',
// DOM refs
canvas: null,
ctx: null,
init() {
this.canvas = document.getElementById('game-canvas');
this.ctx = this.canvas.getContext('2d');
// Set the canvas pixel dimensions
this.canvas.width = 480;
this.canvas.height = 640;
console.log('POP initialized');
},
};
document.addEventListener('DOMContentLoaded', () => POP.init());
  • const POP = { ... } — a plain object used as a namespace. All game state and methods live inside it.
  • this.canvas.getContext('2d') — returns the Canvas 2D rendering context. Every drawing call (fillRect, arc, createRadialGradient, etc.) goes through this object.
  • Pixel dimensions vs. CSS dimensionscanvas.width and canvas.height set the internal pixel grid. CSS width: 100% stretches the canvas visually. You will handle the scaling mismatch in Stage 4 when you implement click detection.
  • DOMContentLoaded — fires when the HTML is fully parsed. Wrapping POP.init() here ensures all the getElementById calls succeed even if the script is moved to the <head> later.

Open index.html in a browser. The CSS you will write in Stage 2 does not exist yet, so the layout will be unstyled — you should still see the canvas element and the start screen text in plain browser defaults.

Check the browser console (F12 → Console) for the POP initialized message. If it appears, the DOM wiring is working.

Troubleshooting:

  • No message in the console? Check that <script src="pop.js"> is at the bottom of <body> and that the filename matches exactly.
  • getContext is not a function? The canvas variable is null, which means getElementById('game-canvas') did not find the element. Check that id="game-canvas" is present in the HTML.

In Stage 2 you will write all the CSS — the dark gradient canvas, the HUD positioning, the overlay screens, and the buttons.