What Is Parallax Scrolling?
Parallax scrolling is one of the oldest and most elegant tricks in game development. The technique creates an illusion of depth by moving background layers at different speeds relative to the camera. Objects closer to the viewer scroll faster, while distant objects barely move at all, exactly mimicking how depth perception works in the real world when you look out of a moving car window.
The term “parallax” comes from the Greek parallaxis, meaning “alteration.” In astronomy, stellar parallax is used to measure distances to nearby stars by observing how their apparent position shifts against the background as Earth orbits the Sun. Game developers borrowed this same principle: by giving each visual layer a different scroll rate proportional to its implied distance, flat 2D scenes suddenly feel three-dimensional.
First popularized in arcade games like Moon Patrol (1982) and Jungle Hunt (1982), parallax scrolling became a staple of the 16-bit era. Games like Sonic the Hedgehog, Street Fighter II, and Donkey Kong Country used multiple parallax layers to create richly layered worlds. Today, modern titles like Hollow Knight, Celeste, Ori and the Blind Forest, and Dead Cells still use it, proof that a technique from 1982 has held up.
The Geometry Behind It
Parallax scrolling exploits a fundamental property of perspective projection. When a camera translates horizontally by some displacement $\Delta x_{\text{cam}}$, an object at depth $d$ appears to shift on screen by:
$$\Delta x_{\text{screen}} = \frac{f \cdot \Delta x_{\text{cam}}}{d}$$
where $f$ is the focal length (or a reference depth constant). The key insight is the inverse relationship between depth and apparent displacement: doubling the distance halves the motion. This is why distant mountains barely drift while nearby trees rush past.
In a layer-based parallax system, we simplify this continuous relationship into discrete layers, each with a scroll factor $s_i$. Given the camera’s current scroll position $x_{\text{cam}}$, each layer’s rendered offset becomes:
$$x_i = x_{\text{cam}} \cdot s_i$$
where $s_i \in [0, 1]$ for background layers behind the main game plane, $s_i = 1$ for the main game layer itself, and $s_i > 1$ for foreground elements closer to the camera. The scroll factor for any layer can be derived from its implied depth:
$$s_i = \frac{d_{\text{ref}}}{d_i}$$
where $d_{\text{ref}}$ is the depth of the reference (gameplay) layer and $d_i$ is the depth of layer $i$. A sky layer at “infinite” distance would have $s \approx 0$, while a foreground bush at half the reference depth would have $s = 2$.
Layer Architecture
A typical parallax scene is organized as a stack of layers, each rendered in back-to-front order (painter’s algorithm). Here is a common setup for a side-scrolling platformer:
- Sky / gradient — $s = 0.0$ (static or near-static)
- Distant clouds — $s = 0.05$ to $0.1$
- Far mountains — $s = 0.15$ to $0.25$
- Near mountains / hills — $s = 0.3$ to $0.5$
- Background foliage — $s = 0.6$ to $0.8$
- Game layer — $s = 1.0$ (tiles, characters, enemies)
- Foreground foliage — $s = 1.2$ to $1.5$
- Weather / particles — $s = 1.5$ to $2.0$
More layers create a smoother depth gradient, but each additional layer costs fill rate. Most games use between 4 and 8 parallax layers, which provides a convincing sense of depth without excessive overdraw.
Basic Implementation
The simplest parallax implementation requires just a few lines of code. Here is the core loop in JavaScript:
// Define layers with their scroll factors
const layers = [
{ image: skyImage, scrollFactor: 0.0 },
{ image: cloudsImage, scrollFactor: 0.1 },
{ image: mountainsImage, scrollFactor: 0.3 },
{ image: treesImage, scrollFactor: 0.7 },
{ image: groundImage, scrollFactor: 1.0 },
];
function render(cameraX) {
for (const layer of layers) {
// Each layer scrolls at its own rate
const offsetX = cameraX * layer.scrollFactor;
// Tile the layer horizontally for infinite scrolling
const wrappedX = ((offsetX % layer.image.width) + layer.image.width)
% layer.image.width;
// Draw twice to cover seams
ctx.drawImage(layer.image, -wrappedX, 0);
ctx.drawImage(layer.image, layer.image.width - wrappedX, 0);
}
}The modulo-based wrapping ensures that each layer tiles seamlessly for infinite scrolling. Drawing the image twice (offset and offset + width) guarantees there is no visible gap at the seam.
Unity / C# Implementation
In Unity, parallax is commonly applied by adjusting each layer’s position relative to the camera every frame:
using UnityEngine;
public class ParallaxLayer : MonoBehaviour
{
public Transform cameraTransform;
public float scrollFactor = 0.5f;
private Vector3 _previousCamPos;
void Start()
{
_previousCamPos = cameraTransform.position;
}
void LateUpdate()
{
// How far the camera moved this frame
Vector3 delta = cameraTransform.position - _previousCamPos;
// Move this layer by a fraction of the camera movement
// (1 - scrollFactor) gives the lag behind the camera
transform.position += delta * (1f - scrollFactor);
_previousCamPos = cameraTransform.position;
}
}Attach this script to each background layer with a different scrollFactor. A value of 0.0 means the layer moves with the camera (stays fixed on screen), while 1.0 means it does not move at all (fully static in world space). This convention is inverted from our math above: the delta-based approach subtracts the camera’s movement, so you are controlling how much each layer lags behind.
Seamless Tiling
For horizontally scrolling games, each parallax layer needs to tile infinitely. The standard technique is to use images that tile seamlessly at their horizontal edges, then render enough copies to fill the viewport. The number of copies needed is:
$$n = \left\lceil \frac{w_{\text{viewport}}}{w_{\text{tile}}} \right\rceil + 1$$
The extra $+1$ ensures coverage during the transition at the wrap point. For non-tiling artwork (like a unique city skyline), you can use a single wide image and clamp the scroll range, or crossfade between segments.
Advanced Techniques
Vertical Parallax
Parallax is not limited to horizontal movement. Many games apply vertical parallax for platformers with significant vertical traversal. The same scroll factor principle applies: the sky moves less than the ground when the camera pans up or down. Celeste uses vertical parallax extensively as the player climbs the mountain, with cloud layers gently drifting at different rates.
Multi-Axis and Rotational Parallax
Some games extend parallax to arbitrary camera transformations. If the camera can rotate, layers at different depths should rotate at different rates around the focal point. The angular displacement for a layer at depth $d$ when the camera rotates by $\theta$ is:
$$\theta_i = \theta \cdot s_i$$
Games like Rayman Legends use subtle multi-axis parallax, with layers responding to both horizontal and vertical camera movement and gentle rotational sway, creating an immersive 2.5D effect.
Depth-Based Blur and Color Grading
To enhance the depth illusion, many modern games apply visual effects that vary per layer. Distant layers receive a slight Gaussian blur (simulating atmospheric perspective) and are tinted toward a haze color, typically a desaturated blue. This is known as aerial perspective and increases the perceived depth separation between layers.
// Apply atmospheric perspective per layer
function getLayerTint(scrollFactor) {
const depth = 1.0 - scrollFactor; // 0 = close, 1 = far
const hazeColor = { r: 0.6, g: 0.7, b: 0.85 };
return {
r: lerp(1.0, hazeColor.r, depth * 0.5),
g: lerp(1.0, hazeColor.g, depth * 0.5),
b: lerp(1.0, hazeColor.b, depth * 0.5),
alpha: lerp(1.0, 0.7, depth * 0.3),
};
}Continuous Parallax (No Discrete Layers)
Instead of using a fixed number of flat layers, some engines assign a depth value to individual sprites or tiles and compute their scroll offset continuously. This avoids the “layer cake” look where several objects clearly share the same depth plane. The offset for each object is simply:
$$x_{\text{obj}} = x_{\text{world}} - x_{\text{cam}} \cdot \left(1 - \frac{d_{\text{ref}}}{d_{\text{obj}}}\right)$$
Hollow Knight applies this approach throughout: background elements like stalactites, ruined architecture, and ambient creatures each have slightly different depth values, creating an organic, layered world that never feels flat.
Performance Considerations
Parallax scrolling is lightweight compared to most rendering techniques, but there are a few pitfalls to watch for:
- Overdraw: Each layer covers the full screen. With 8 layers, you are filling the screen 8 times per frame. On mobile GPUs with limited fill rate, this adds up. Use opaque layers where possible and minimize transparent regions.
- Texture memory: Large, high-resolution parallax layers consume significant VRAM. Consider using tiling textures (which can be much smaller) or compressed formats like ASTC or BC7.
- Sub-pixel scrolling: When layers scroll at very slow rates, movement can appear jittery due to pixel snapping. Either round positions to whole pixels (for a crisp pixel-art look) or enable texture filtering for smooth sub-pixel rendering.
- Camera bounds: Ensure parallax layers extend far enough that they do not reveal empty space at the screen edges, especially when the camera reaches level boundaries. A common fix is to make each layer wider than the viewport by a margin proportional to its scroll range.
Games That Defined Parallax Scrolling
Moon Patrol (1982) — One of the earliest games to use parallax scrolling, with three background layers moving at different speeds behind the lunar rover.
Sonic the Hedgehog (1991) — The Genesis classic used up to 6 parallax layers in some zones, with the iconic Green Hill Zone featuring rolling hills, waterfalls, and checkered patterns all scrolling independently.
Donkey Kong Country (1994) — Rare pushed the SNES hardware with pre-rendered 3D sprites and elaborate parallax backgrounds that gave the game a visual depth unusual for 16-bit hardware.
Hollow Knight (2017) — Team Cherry’s game uses continuous parallax with individually placed background elements, atmospheric color grading, and particle effects to produce some of the most layered environments in 2D games.
Dead Cells (2018) — Motion Twin combines parallax scrolling with dynamic lighting and procedurally generated levels, proving that parallax works well with randomized content.
Wrapping Up
Parallax scrolling shows how a simple mathematical principle, that closer things move faster, can transform flat artwork into immersive worlds. The technique is easy to implement, cheap to run, and scales gracefully from retro pixel art to hand-painted backgrounds. Adding a few parallax layers to any game scene gives it immediate visual depth, whether you are building a platformer, an RPG, or just a title screen.
Try the interactive demo above to see parallax in action. Move your mouse (or finger) across the scene and watch how each layer (stars, moon, mountains, hills, trees, and ground) responds at a different rate, creating that sense of depth from nothing more than flat shapes and clever math.
Comments