Your first shader is mostly boilerplate
·2 min read ·WebGL · JavaScript · Frontend
The first time I opened a raw WebGL tutorial, I saw a hundred lines of code to draw one triangle and closed the tab. That reaction is almost universal, and it's based on a misunderstanding. Most of those lines are plumbing. You write them once, wrap them in three helper functions, and never think about them again.
The part that matters is two small programs.
The two-question mental model
Every shader pipeline answers exactly two questions.
The vertex shader runs once per vertex and answers: where does this point land on screen? The fragment shader runs once per pixel and answers: what color is this pixel?
That's it. Lighting, fog, water, outlines, the wobble on a hover effect—every visual trick you have ever seen is a creative answer to one of those two questions.
// vertex: where does this point go?
gl_Position = projection * view * model * vec4(position, 1.0);
// fragment: what color is this pixel?
gl_FragColor = vec4(vUv, 0.5, 1.0);
Two lines of real logic. Everything else in the tutorial exists to deliver data to those two lines.
The wall is 30 lines, and you climb it once
The boilerplate breaks down into a handful of jobs: compile two shader strings, link them into a program, upload vertex data into a buffer, and tell WebGL how to read that buffer. Each job is a short function with an ugly API. None of it is conceptually hard—it's a state machine where you bind a thing, configure the bound thing, and move on.
Write createShader, createProgram, and createBuffer once. Every demo you build afterwards reuses them unchanged. The hundred-line triangle becomes a ten-line triangle plus a utility file you stop reading.
Why bother, when Three.js exists
Three.js hides all of this, and in production you should let it. I use it for everything serious I build with 3D.
But I only really understood Three.js after writing the raw version once. Suddenly a Material was obviously a shader pair plus uniforms. A BufferGeometry was obviously the buffers I had uploaded by hand. The renderer was obviously the state machine I had fought directly. Debugging stopped being guesswork because the abstraction stopped being magic.
Spend one afternoon drawing a triangle the hard way. It's the cheapest mental model in graphics, and it never expires.