← Back to the WebGL tutorial
Lesson

WebGL, Visually

WebGL draws hardware-accelerated 2D and 3D graphics right in a <canvas> — no plugins, talking straight to the GPU. This lesson explains the rendering pipeline, shaders, and coordinates, shows you raw WebGL and a friendly library, with two live demos running on your graphics card right now.

Step 1

What WebGL is

WebGL (Web Graphics Library) is a JavaScript API for drawing graphics with the GPU — the same chip that powers video games. It renders into an ordinary <canvas> element, so 3D scenes, particle fields, data visualizations, and shader art run in the browser with no plugins.

Unlike HTML and CSS, which describe boxes of content, WebGL gives you a blank pixel grid and total control over every pixel — at the cost of doing a lot more work yourself. It's based on OpenGL ES, the graphics standard used on phones and consoles.

The trade-off in one line: WebGL is the most powerful and the most low-level way to draw on the web. Enormous capability, steep setup — which is why most people use a library on top of it (Step 7).
Step 2

The canvas & the context

Everything starts with a <canvas> and a rendering context. Asking the canvas for its "webgl" context hands you the object through which every GPU command flows.

<canvas id="scene" width="600" height="400"></canvas>

const canvas = document.getElementById('scene');
const gl = canvas.getContext('webgl');   the gateway to the GPU

gl.clearColor(0.05, 0.05, 0.1, 1);    RGBA, each 0–1
gl.clear(gl.COLOR_BUFFER_BIT);     paint the canvas
Colors are 0–1, not 0–255. WebGL speaks the GPU's language, where every channel is a float from 0 to 1. 1.0 is full intensity; CSS's 255 becomes 1.0.
Step 3

The rendering pipeline

The GPU turns your data into pixels in a fixed sequence of stages. Understanding this flow is the key to all of WebGL:

Verticespoints you supply
Vertex shaderpositions each point
Rasterizeshapes → fragments
Fragment shadercolors each pixel
Pixelson screen

You feed in a list of vertices (corner points). The vertex shader decides where each lands on screen. The GPU rasterizes the shapes into fragments (pixel-sized pieces). The fragment shader picks a color for each one. The result is drawn.

The two green stages are the parts you program — the shaders. Everything else the GPU handles. Master shaders and you've mastered WebGL.
Step 4

Shaders: tiny programs on the GPU

A shader is a small program written in GLSL that runs in massive parallel on the GPU — thousands of cores at once. There are two kinds, one for each green stage above:

ShaderRuns once per…Job
Vertexvertex (corner point)Output the point's final position (gl_Position).
Fragmentpixel (fragment)Output that pixel's color (gl_FragColor).

A minimal pair

// vertex shader — place the point
attribute vec2 a_pos;
void main() {
  gl_Position = vec4(a_pos, 0.0, 1.0);
}

// fragment shader — color the pixel (lime green)
precision mediump float;
void main() {
  gl_FragColor = vec4(0.52, 0.80, 0.09, 1.0);
}
Data gets into shaders through three channel types: attributes (per-vertex data like position), uniforms (one value for the whole draw, like time or a color), and varyings (values passed vertex → fragment and smoothly blended).
Step 5

Live: a fragment shader, running now

This canvas draws two triangles that cover the whole frame, then a fragment shader computes a color for every pixel from its position and a u_time uniform. The GPU re-runs it ~60 times a second — that's the animation. Raw WebGL, no library.

Raw WebGL · fragment shader
precision mediump float;
uniform float u_time;
uniform vec2 u_res;
void main() {
  vec2 uv = gl_FragCoord.xy / u_res;
  float v = sin(uv.x*10.+u_time) + sin(uv.y*10.+u_time);
  gl_FragColor = vec4(0.5+0.5*cos(v+vec3(0.,2.,4.)), 1.);
}
Notice there is no loop over pixels in your code. You write the color formula once; the GPU runs it for every pixel simultaneously. That parallelism is why WebGL can do things CSS never could.
Step 6

Coordinates & buffers

WebGL's screen is clip space: the center is (0, 0), the left edge is -1, the right edge +1, bottom -1, top +1 — regardless of pixel size. Your vertex shader outputs positions in this space.

You send vertex data to the GPU in a buffer (a typed array), then describe its layout with an attribute. A full-screen quad is just four corners:

const verts = new Float32Array([
  -1,-1,  1,-1,  -1,1,    triangle 1
  -1,1,   1,-1,  1,1      triangle 2
]);
const buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW);
Everything is triangles. The GPU only draws triangles — a rectangle is two, a sphere is thousands. Even the smooth shader demo above is painted across two big triangles.
Step 7

Why almost everyone uses a library

A spinning cube in raw WebGL is ~150 lines of shader compilation, buffer setup, and matrix math. Libraries like Three.js wrap all of it in friendly objects — scenes, cameras, meshes, lights — so the same cube is a dozen readable lines.

import * as THREE from 'three';

const scene  = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, 1.6, 0.1, 100);
const renderer = new THREE.WebGLRenderer({ antialias: true });

const cube = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshStandardMaterial({ color: 0x84cc16 })
);
scene.add(cube);
The library still uses WebGL under the hood — it just spares you the boilerplate. Three.js is the most popular; Babylon.js, PlayCanvas, and PixiJS (2D) are other strong choices.
Step 8

Live: a Three.js 3D cube

Here's that cube, lit and spinning — real 3D, rendered through WebGL by Three.js. Same GPU pipeline from Step 3, just with the boilerplate handled for you:

Three.js · WebGL
A mesh = geometry (the shape's vertices) + material (how its surface responds to light). Add lights and a camera, then call renderer.render(scene, camera) each frame inside requestAnimationFrame — that loop is what makes it spin.
Step 9

WebGL, Canvas 2D, or CSS/SVG?

WebGL is powerful but heavy. Reach for the lightest tool that does the job:

NeedUse
Buttons, layout, simple hover/scroll motionCSS — cheap, accessible, no canvas.
Icons, charts, crisp scalable shapesSVG — vector, stylable, in the DOM.
2D games, image filters, lots of spritesCanvas 2D — per-pixel, simpler API than WebGL.
3D, shaders, 10,000s of objects, GPU effectsWebGL (usually via Three.js).
Accessibility & cost: canvas pixels are invisible to screen readers — provide text alternatives and don't put essential content only in WebGL. It also drains battery and can fail on weak GPUs, so offer a fallback and pause rendering when off-screen.
Step 10

WebGL checklist

Where next

Keep going