WebGL, 2011

WebGL put a 3D API behind a browser canvas with no plugin. This era calls it raw from JavaScript with no library: query the context and its limits, fill buffers, link shader programs, set GL state and issue draw calls, with every gl.* call printed back.

Graphics track · 28 missions · boss mission, written exam and certificate · free, no signup. Everything below runs in the browser terminal on the SERVBG home page.

Open WebGL in the terminal

What you will do

  1. see the reference scene drawn by this era, as a texture on two triangles ref

    Before 2011 a picture like this in a browser meant a plugin. WebGL 1.0 was released on 3 March 2011 and made it fifteen lines of JavaScript against the graphics card.

  2. query the live context: version, renderer and hardware limits context

    getContext("webgl2") returns null rather than throwing when the browser refuses, which is why every serious WebGL page starts with a fallback to "webgl" and then to a static image.

  3. read how a 3D API got into the browser, with dates timeline

    Vladimir Vukicevic started Canvas 3D at Mozilla in 2006; Khronos took it into a working group in March 2009 with Mozilla, Google, Apple and Opera; the 1.0 spec landed in March 2011.

  4. walk the fixed stages every draw call passes through pipeline

    You write two stages, the vertex shader and the fragment shader. Primitive assembly, clipping, the perspective divide, the viewport transform and rasterisation are fixed hardware you only configure.

  5. wipe the framebuffer with gl.clearColor and gl.clear clear 0.05 0.06 0.09

    clearColor stores a colour, clear applies it. GL colours are floats from 0.0 to 1.0, a convention inherited from OpenGL in 1992 and unchanged since.

  6. read and compile the vertex shader shader vert

    A vertex shader has one required output: gl_Position, a vec4 in clip space. It runs once per vertex, in parallel, with no access to any other vertex.

  7. read and compile the fragment shader shader frag

    The precision line is mandatory: GLSL ES gives fragment floats no default precision, so a fragment shader without it fails to compile.

  8. attach both shaders, link them and check LINK_STATUS program link

    Linking matches the two shaders up. Every varying the fragment shader reads must be written by the vertex shader with the same name and type, or the link fails even though both compiled.

  9. upload three vertices to the GPU with gl.bufferData buffer create

    bufferData writes into whatever is bound to the target, not into the buffer you pass it, because there is no buffer argument. WebGL is a state machine and this is the part that catches everyone once.

  10. wire the buffer to the shader attribute: size, type, stride, offset attrib a_pos 2

    vertexAttribPointer captures the buffer bound at that instant. Bind the wrong one a line earlier and you get garbage geometry with no error raised at all.

  11. set a value that is constant for the whole draw call uniform u_color 1 0.5 0

    Attribute varies per vertex, varying is interpolated per fragment, uniform is one value for the entire draw call. The suffix on uniform3f names the payload, not the uniform.

  12. issue the first real draw call, gl.drawArrays draw triangle

    The count argument is vertices, not triangles: gl.TRIANGLES consumes them in threes. The triangle is the only filled primitive the hardware knows.

  13. read one pixel back out of the framebuffer and check the colour readpixel 160 140

    readPixels stalls the pipeline: the CPU must wait for every queued GPU command before it can answer, which is why it belongs in tests and screenshots, never in a render loop.

  14. make a deliberate mistake and decode what gl.getError returns error

    WebGL never throws for a GL mistake. It sets a flag that stays set until something reads it, so getError returns the first error since the last read and then resets to NO_ERROR.

  15. upload four vertices with position and texture coordinate interleaved buffer quad

    Interleaving beats two separate buffers because one vertex is one contiguous 16-byte read: one cache line touched instead of two.

  16. describe two triangles out of four vertices with an index buffer indices

    drawElements arrived in OpenGL 1.1 in 1997 so a shared vertex could be uploaded once and referenced many times. UNSIGNED_SHORT indices cap a mesh at 65,536 vertices.

  17. upload the reference image to the GPU with gl.texImage2D texture load

    UNPACK_FLIP_Y_WEBGL exists because HTML images start at the top-left while texture coordinate v = 0 means the bottom. Without the flip the picture arrives upside down.

  18. bind the texture to a texture unit and point the sampler at it sampler

    A sampler2D uniform holds a texture unit number, so it is set with uniform1i. Passing the texture object instead is the most common WebGL texture bug there is.

  19. switch the texture from nearest to bilinear sampling filter linear

    MIN_FILTER applies when the texture is squeezed, MAG_FILTER when it is stretched. Bilinear filtering has been free in silicon since the 3dfx Voodoo in 1996.

  20. draw the textured quad with gl.drawElements draw quad

    The second, smaller square is drawn last and sits farther away, yet it paints over the picture. With no depth test, draw order is the only order there is.

  21. enable the depth test and watch the far square go behind depth on

    Z-fighting is the depth buffer running out of precision: two nearly coplanar surfaces land in the same 24-bit bucket and flicker. Moving the near plane out from 0.001 to 0.1 fixes more of it than anything else.

  22. enable alpha blending with the standard source-over function blend on

    SRC_ALPHA with ONE_MINUS_SRC_ALPHA is the source-over operator Porter and Duff defined in 1984. Blended geometry has to be sorted back to front, because it needs whatever is behind it already drawn.

  23. ask the context what is actually switched on right now state

    There is no call that returns the whole context state. Renderers keep a shadow copy in JavaScript and only call gl.* when a value really changed, because a function that flips a switch and forgets to flip it back breaks code it never touched.

  24. shrink the viewport and see NDC squeezed into a corner resize 160 120

    The viewport maps normalised device coordinates, always -1 to +1, onto a pixel rectangle. gl.clear ignores it and wipes the whole drawing buffer regardless.

  25. match the viewport back to the drawing buffer resize 320 240

    A canvas has two sizes: the drawing buffer in pixels and the CSS box it is stretched into. Letting them drift apart is why so much WebGL looks blurry, and forgetting the viewport call after a resize is why the rest looks stretched.

  26. read the render loop and why it is driven by delta time loop

    Robert O'Callahan proposed requestAnimationFrame at Mozilla in 2010. It fires once per display refresh and stops completely in a hidden tab, which is exactly why animation is scaled by elapsed seconds and not by frame count.

  27. see what WebGL 2.0 added in 2017 and how GLSL changed webgl2

    The WebGL 2.0 specification was released on 17 January 2017 on top of OpenGL ES 3.0: vertex array objects, instancing, 3D textures and transform feedback all became core, and GLSL ES 3.00 replaced attribute and varying with in and out.

  28. Boss missionanimate the rotation uniform — textured quad, depth test and blending on spin

    One float and one draw call per frame is the whole idea: geometry uploaded once and transformed by a uniform, instead of the 1990s habit of pushing every vertex across the bus every frame.

Certificate

This track is certifiable. Clear the boss mission in the terminal, then run EXAM WEBGL for the written paper: 20 server-graded questions drawn from our own bank, pass mark 14 of 20. The certificate is issued once both are done, and it carries a verification code.

Nearby eras

Previous
2001 · SHADERS
Write GLSL in a live fragment-shader sandbox: the programmable pipeline, varyings and uniforms, signed distance fields, lighting, errors.
Next
2023 · MODERN GPU
Modern GPU work: explicit APIs, WebGPU adapters, WGSL compute shaders, ray and path tracing, denoising, upscaling, tensor cores.

All 25 eras in the Terminal Academy

Open WebGL in the terminal