6-space-game/2-drawing-to-canvas/README.md
journey
title Your Canvas Graphics Journey
section Foundation
Understand Canvas API: 3: Student
Learn coordinate system: 4: Student
Draw basic shapes: 4: Student
section Image Handling
Load game assets: 4: Student
Handle async loading: 5: Student
Position sprites: 5: Student
section Game Rendering
Create game screen: 5: Student
Build formations: 5: Student
Optimize performance: 4: Student
The Canvas API is one of web development's most powerful features for creating dynamic, interactive graphics right in your browser. In this lesson, we'll transform that blank HTML <canvas> element into a game world filled with heroes and monsters. Think of the canvas as your digital art board where code becomes visual.
We're building on what you learned in the previous lesson, and now we'll dive into the visual aspects. You'll learn how to load and display game sprites, position elements precisely, and create the visual foundation for your space game. This bridges the gap between static web pages and dynamic, interactive experiences.
By the end of this lesson, you'll have a complete game scene with your hero ship positioned correctly and enemy formations ready for battle. You'll understand how modern games render graphics in browsers and gain skills to create your own interactive visual experiences. Let's explore canvas graphics and bring your space game to life!
mindmap
root((Canvas Graphics))
Canvas Element
HTML5 Feature
2D Context
Coordinate System
Pixel Control
Drawing Operations
Basic Shapes
Text Rendering
Image Display
Path Drawing
Asset Management
Image Loading
Async Operations
Error Handling
Performance
Game Rendering
Sprite Positioning
Formation Layout
Scene Composition
Frame Updates
Visual Effects
Colors & Styles
Transformations
Animations
Layering
So what exactly is this <canvas> element? It's HTML5's solution for creating dynamic graphics and animations in web browsers. Unlike regular images or videos that are static, the canvas gives you pixel-level control over everything that appears on screen. This makes it perfect for games, data visualizations, and interactive art. Think of it as a programmable drawing surface where JavaScript becomes your paintbrush.
By default, a canvas element looks like a blank, transparent rectangle on your page. But that's where the potential lies! Its real power emerges when you use JavaScript to draw shapes, load images, create animations, and make things respond to user interactions. It's similar to how early computer graphics pioneers at Bell Labs in the 1960s had to program every pixel to create the first digital animations.
ā Read more about the Canvas API on MDN.
Here's how it's typically declared, as part of the page's body:
<canvas id="myCanvas" width="200" height="100"></canvas>
Here's what this code does:
id attribute so you can reference this specific canvas element in JavaScriptwidth in pixels to control the canvas's horizontal sizeheight in pixels to determine the canvas's vertical dimensionsNow that you know what the canvas element is, let's explore actually drawing on it! The canvas uses a coordinate system that might feel familiar from math class, but there's one important twist specific to computer graphics.
The canvas uses Cartesian coordinates with an x-axis (horizontal) and y-axis (vertical) to position everything you draw. But here's the key difference: unlike the coordinate system from math class, the origin point (0,0) starts at the top-left corner, with x-values increasing as you move right and y-values increasing as you move down. This approach dates back to early computer displays where electron beams scanned from top to bottom, making top-left the natural starting point.
quadrantChart
title Canvas Coordinate System
x-axis Left --> Right
y-axis Top --> Bottom
quadrant-1 Quadrant 1
quadrant-2 Quadrant 2
quadrant-3 Quadrant 3
quadrant-4 Quadrant 4
Origin Point: [0.1, 0.1]
Hero Center: [0.5, 0.8]
Enemy Formation: [0.3, 0.2]
Power-up: [0.7, 0.6]
UI Elements: [0.9, 0.1]
Image from MDN
To draw on the canvas element, you'll follow the same three-step process that forms the foundation of all canvas graphics. Once you do this a few times, it becomes second nature:
flowchart LR
A[HTML Canvas Element] --> B[Get Canvas Reference]
B --> C[Get 2D Context]
C --> D[Drawing Operations]
D --> E[Draw Shapes]
D --> F[Draw Text]
D --> G[Draw Images]
D --> H[Apply Styles]
E --> I[Render to Screen]
F --> I
G --> I
H --> I
style A fill:#e1f5fe
style C fill:#e8f5e8
style I fill:#fff3e0
Here's how this looks in code:
// Step 1: Get the canvas element
const canvas = document.getElementById("myCanvas");
// Step 2: Get the 2D rendering context
const ctx = canvas.getContext("2d");
// Step 3: Set fill color and draw a rectangle
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 200, 200); // x, y, width, height
Let's break this down step by step:
fillStyle propertyā The Canvas API mostly focuses on 2D shapes, but you can also draw 3D elements to a web site; for this, you might use the WebGL API.
You can draw all sorts of things with the Canvas API like:
ā Try it! You know how to draw a rectangle, can you draw a circle to a page? Take a look at some interesting Canvas drawings on CodePen. Here's a particularly impressive example.
Canvas Fundamentals Understanding: Before moving to image loading, ensure you can:
Quick Self-Test: How would you draw a blue circle at position (100, 50) with radius 25?
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(100, 50, 25, 0, 2 * Math.PI);
ctx.fill();
Canvas Drawing Methods You Now Know:
Drawing basic shapes is useful for getting started, but most games need actual images! Sprites, backgrounds, and textures are what give games their visual appeal. Loading and displaying images on the canvas works differently than drawing geometric shapes, but it's straightforward once you understand the process.
We need to create an Image object, load our image file (this happens asynchronously, meaning "in the background"), and then draw it to the canvas once it's ready. This approach ensures your images display properly without blocking your application while they load.
sequenceDiagram
participant JS as JavaScript
participant Img as Image Object
participant Server as File Server
participant Canvas as Canvas Context
JS->>Img: new Image()
JS->>Img: Set src property
Img->>Server: Request image file
Server->>Img: Return image data
Img->>JS: Trigger onload event
JS->>Canvas: drawImage(img, x, y)
Canvas->>Canvas: Render to screen
Note over JS,Canvas: Async loading prevents UI blocking
const img = new Image();
img.src = 'path/to/my/image.png';
img.onload = () => {
// Image loaded and ready to be used
console.log('Image loaded successfully!');
};
Here's what's happening in this code:
Here's a more robust way to handle image loading that professional developers commonly use. We'll wrap the image loading in a Promise-based function ā this approach, popularized when JavaScript Promises became standard in ES6, makes your code more organized and handles errors gracefully:
function loadAsset(path) {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = path;
img.onload = () => {
resolve(img);
};
img.onerror = () => {
reject(new Error(`Failed to load image: ${path}`));
};
});
}
// Modern usage with async/await
async function initializeGame() {
try {
const heroImg = await loadAsset('hero.png');
const monsterImg = await loadAsset('monster.png');
// Images are now ready to use
} catch (error) {
console.error('Failed to load game assets:', error);
}
}
What we've done here:
Once your images are loaded, drawing them to the canvas is actually pretty straightforward:
async function renderGameScreen() {
try {
// Load game assets
const heroImg = await loadAsset('hero.png');
const monsterImg = await loadAsset('monster.png');
// Get canvas and context
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// Draw images to specific positions
ctx.drawImage(heroImg, canvas.width / 2, canvas.height / 2);
ctx.drawImage(monsterImg, 0, 0);
} catch (error) {
console.error('Failed to render game screen:', error);
}
}
Let's walk through this step by step:
flowchart TD
A[Load Assets] --> B{All Images Loaded?}
B -->|No| C[Show Loading]
B -->|Yes| D[Get Canvas Context]
C --> B
D --> E[Clear Screen]
E --> F[Draw Background]
F --> G[Draw Enemy Formation]
G --> H[Draw Hero Ship]
H --> I[Apply Visual Effects]
I --> J[Render Frame]
subgraph "Rendering Pipeline"
K[Asset Management]
L[Scene Composition]
M[Drawing Operations]
N[Frame Output]
end
style A fill:#e1f5fe
style J fill:#e8f5e8
style I fill:#fff3e0
Now we'll put everything together to create the visual foundation of your space game. You have a solid understanding of canvas fundamentals and image loading techniques, so this hands-on section will guide you through building a complete game screen with properly positioned sprites.
You will build a web page with a Canvas element. It should render a black screen 1024*768. We've provided you with two images:
Hero ship
5*5 monster
Locate the starter files that have been created for you in the your-work sub folder. Your project structure should contain:
your-work/
āāā assets/
ā āāā enemyShip.png
ā āāā player.png
āāā index.html
āāā app.js
āāā package.json
Here's what you're working with:
assets/ folder so everything stays organizedOpen this folder in Visual Studio Code to begin development. You'll need a local development environment with Visual Studio Code, NPM, and Node.js installed. If you don't have npm set up on your computer, here's how to install it.
Start your development server by navigating to the your-work folder:
cd your-work
npm start
This command does some pretty cool stuff:
http://localhost:5000 so you can test your gameš” Note: Your browser will show a blank page initially ā that's expected! As you add code, refresh your browser to see your changes. This iterative development approach is similar to how NASA built the Apollo guidance computer ā testing each component before integrating it into the larger system.
Add the required code to your-work/app.js to complete the following tasks:
Draw a canvas with black background
š” Here's how: Find the TODO in
/app.jsand add just two lines. Setctx.fillStyleto black, then usectx.fillRect()starting at (0,0) with your canvas dimensions. Easy!
Load game textures
š” Here's how: Use
await loadAsset()to load your player and enemy images. Store them in variables so you can use them later. Remember ā they won't show up until you actually draw them!
Draw hero ship in the center-bottom position
š” Here's how: Use
ctx.drawImage()to position your hero. For the x-coordinate, trycanvas.width / 2 - 45to center it, and for y-coordinate usecanvas.height - canvas.height / 4to put it in the bottom area.
Draw a 5Ć5 formation of enemy ships
š” Here's how: Find the
createEnemiesfunction and set up a nested loop. You'll need to do some math for spacing and positioning, but don't worry ā I'll show you exactly how!
First, establish constants for proper enemy formation layout:
const ENEMY_TOTAL = 5;
const ENEMY_SPACING = 98;
const FORMATION_WIDTH = ENEMY_TOTAL * ENEMY_SPACING;
const START_X = (canvas.width - FORMATION_WIDTH) / 2;
const STOP_X = START_X + FORMATION_WIDTH;
Let's break down what these constants do:
flowchart LR
A["Canvas Width: 1024px"] --> B["Formation Width: 490px"]
B --> C["Start X: 267px"]
C --> D["Enemy Spacing: 98px"]
subgraph "5x5 Enemy Formation"
E["Row 1: Y=0"]
F["Row 2: Y=50"]
G["Row 3: Y=100"]
H["Row 4: Y=150"]
I["Row 5: Y=200"]
end
subgraph "Column Spacing"
J["Col 1: X=267"]
K["Col 2: X=365"]
L["Col 3: X=463"]
M["Col 4: X=561"]
N["Col 5: X=659"]
end
style A fill:#e1f5fe
style B fill:#e8f5e8
style C fill:#fff3e0
Then, create nested loops to draw the enemy formation:
for (let x = START_X; x < STOP_X; x += ENEMY_SPACING) {
for (let y = 0; y < 50 * 5; y += 50) {
ctx.drawImage(enemyImg, x, y);
}
}
Here's what this nested loop does:
Game Rendering Mastery: Verify your understanding of the complete rendering system:
Performance Considerations: Your game now demonstrates:
Visual Programming Concepts: You've learned:
The finished result should look like so:
Please try solving it yourself first but if you get stuck, have a look at a solution
Use the Agent mode to complete the following challenge:
Description: Enhance your space game canvas by adding visual effects and interactive elements using the Canvas API techniques you've learned.
Prompt: Create a new file called enhanced-canvas.html with a canvas that displays animated stars in the background, a pulsing health bar for the hero ship, and enemy ships that slowly move downward. Include JavaScript code that draws twinkling stars using random positions and opacity, implements a health bar that changes color based on health level (green > yellow > red), and animates the enemy ships to move down the screen at different speeds.
Learn more about agent mode here.
You've learned about drawing with the 2D-focused Canvas API; take a look at the WebGL API, and try to draw a 3D object.
Learn more about the Canvas API by reading about it.
document.createElement('canvas')fillRect() on a canvas contextfillStyle propertyarc() methodtimeline
title Canvas API Learning Progression
section Canvas Fundamentals (15 minutes)
Basic Operations: Element reference
: 2D context access
: Coordinate system
: Simple shape drawing
section Drawing Techniques (20 minutes)
Graphics Primitives: Rectangles and circles
: Colors and styles
: Text rendering
: Path operations
section Image Handling (25 minutes)
Asset Management: Image object creation
: Async loading patterns
: Error handling
: Performance optimization
section Game Graphics (30 minutes)
Sprite Rendering: Positioning algorithms
: Formation calculations
: Scene composition
: Frame rendering
section Advanced Techniques (40 minutes)
Visual Effects: Transformations
: Animations
: Layering
: State management
section Performance (35 minutes)
Optimization: Efficient drawing
: Memory management
: Frame rate control
: Asset caching
section Professional Skills (1 week)
Production Graphics: WebGL integration
: Canvas libraries
: Game engines
: Cross-platform considerations
section Advanced Graphics (1 month)
Specialized Applications: Data visualization
: Interactive art
: Real-time effects
: 3D graphics
After completing this lesson, you now have:
Real-World Applications: Your Canvas skills directly apply to:
Professional Skills Gained: You can now:
Canvas API Methods You've Mastered:
Next Level: You're ready to add animation, user interaction, collision detection, or explore WebGL for 3D graphics!
š Achievement Unlocked: You've built a complete game rendering system using fundamental Canvas API techniques!