May 27, 2026

Game Development Basics: HTML5 Canvas & JavaScript

Building games used to require complex software suites, expensive licenses, and compiling highly specialized code. Today, the most accessible and versatile game development platform in the world is already installed on your computer: the modern web browser. With just a simple text editor and an understanding of HTML5 and JavaScript, anyone can engineer high-performance, responsive arcade games that run seamlessly across desktops and mobile devices. At the heart of this web gaming revolution is the HTML5 <canvas> element. In this comprehensive technical guide, we will break down the foundational concepts of browser-based game development, covering everything from establishing a rendering loop to implementing basic physics and collision detection.

Canvas API Setup and the Game Loop

The <canvas> element is exactly what it sounds like: a blank digital slate. However, HTML alone cannot draw on it. You must use JavaScript to access the canvas's "rendering context," which provides a massive API of drawing functions. To begin, you grab the element via document.getElementById() and request the '2d' context. Once you have the context, you can instruct it to draw rectangles, paths, text, and images pixel by pixel.

But drawing a static image is not a game. A game requires motion, which means the canvas must be rapidly cleared and redrawn multiple times per second. This is achieved via the game loop. The modern standard for creating a game loop in JavaScript is requestAnimationFrame(). Unlike older methods like setInterval(), requestAnimationFrame() synchronizes the redrawing of your game with the browser's own display refresh rate (typically 60 frames per second). It provides incredibly smooth animations and automatically pauses the loop when the user switches to a different tab, preserving battery life and CPU resources.

Sprite Rendering Code Examples

In game development, a "sprite" refers to a 2D bitmap graphic that represents a character, item, or background element. While the canvas API allows you to draw primitive shapes using commands like fillRect() and arc(), most professional games use pre-rendered image files for their sprites. Drawing an image to the canvas is remarkably simple using the drawImage() method.

A common optimization technique is using a "sprite sheet"—a single large image file containing multiple animation frames or different assets. By passing additional parameters to drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight), you can instruct the canvas to only clip and render a specific rectangular portion of the sprite sheet. By updating the source X and Y coordinates (sx, sy) within your game loop, you can cycle through a character's walk cycle seamlessly without having to load dozens of separate image files.

Collision Detection: AABB vs. Circle

If you can draw a player and you can move a player, the next step is making the player interact with the environment. This requires collision detection. The most fundamental and widely used algorithm for 2D games is Axis-Aligned Bounding Box (AABB) collision. "Axis-Aligned" simply means the rectangles are not rotated; their edges are perfectly parallel to the X and Y axes of the screen. To check if two rectangles (RectA and RectB) are overlapping, you evaluate a simple boolean statement: (RectA.x < RectB.x + RectB.width && RectA.x + RectA.width > RectB.x && RectA.y < RectB.y + RectB.height && RectA.y + RectA.height > RectB.y). If all four conditions are true, a collision has occurred.

AABB is perfect for platformers or games like Pong. However, if your game features rounded objects—like an asteroid or a bouncing ball—AABB can feel inaccurate because the invisible rectangular corners might trigger collisions when the visual circles haven't touched. In these cases, you use Circle Collision. This involves calculating the distance between the center points of the two circles using the Pythagorean theorem. If the calculated distance is less than the sum of the two circles' radii, they have collided. It is slightly more computationally expensive due to the square root math, but it provides perfect accuracy for round entities.

Basic Physics: Velocity, Gravity, and Friction

Creating believable movement requires applying rudimentary Newtonian physics to your game objects. Instead of manually updating a character's X and Y position, you give the character velocityX and velocityY properties. Every frame, you add the velocity to the position. This allows for smooth, continuous movement.

To implement gravity (crucial for platformers like Mario or endless runners like Flappy Bird), you simply define a constant gravity variable (e.g., const gravity = 0.5;) and continuously add it to the character's velocityY every frame. This causes the character to accelerate downward, creating a realistic parabolic arc when they jump. Friction is implemented similarly to slow objects down gradually. By multiplying a character's horizontal velocity by a friction coefficient (e.g., velocity *= 0.9;), the character will slide to a smooth, realistic halt when the player stops pressing the directional key.

Delta Time Explained

One of the most critical concepts for cross-platform game development is Delta Time. By default, if you move a character 5 pixels every frame, that character will move much faster on a 144Hz gaming monitor than on a standard 60Hz office monitor, because the game loop is firing more frequently. This leads to wildly inconsistent gameplay experiences across different hardware.

Delta Time (usually represented as dt) solves this. It is the measurement of the exact milliseconds that have passed since the last frame was rendered. Instead of moving an object by a fixed pixel amount per frame, you define movement as pixels per second, and multiply it by the Delta Time. For example: position.x += speed * dt;. If the computer experiences a lag spike and the frame takes twice as long to render, the Delta Time will be twice as large, meaning the character will move twice as far on that specific frame. This ensures that game speed remains perfectly consistent regardless of the device's framerate.

Keyboard Input Handling

Handling user input asynchronously is vital. If you simply check for keydown events, you will encounter operating system-level key delays. The standard practice is to create a global input object or array that acts as a state map. When a keydown event fires, you set that specific key's status to true. When a keyup event fires, you set it to false.

Inside your main game loop, you evaluate the state of this input map. If keys['ArrowRight'] is true, you apply positive horizontal velocity to the player. This polling method allows the game loop to respond instantly and smoothly to multiple keys being held down simultaneously, enabling complex movements like running and jumping at the same time.

Key Takeaways

Frequently Asked Questions

What is the HTML5 Canvas?

The HTML5 Canvas is an element that acts as a container for graphics, allowing developers to draw shapes, text, and images programmatically using JavaScript.

Why use requestAnimationFrame?

It is optimized by the browser to run at the display's refresh rate (typically 60fps), providing a smooth, flicker-free game loop while saving battery life when the tab is inactive.

What is AABB collision detection?

Axis-Aligned Bounding Box (AABB) is a simple collision detection method used for non-rotated rectangles, commonly used in 2D platformers and arcade games.

What is Delta Time?

Delta Time is the time passed between the current frame and the last frame. Using it ensures your game runs at the same speed regardless of the device's framerate.

Play Related Games on Movuter Arcade

See these Canvas HTML5 principles in action! Our games rely on optimized game loops and flawless physics. Try them out and analyze their mechanics. Play Tetris, Play Snake, Play Brick Breaker

Sarah Chen

Sarah Chen

Lead Engine Developer

Web graphics specialist focused on writing hyper-optimized vanilla JavaScript to push browser capabilities to their absolute limit.