Skip to content
cccskills
FreePublished on GitHub

glsl-fundamentals

The GLSL itself - which dialect a shader is in, what precision means, the types and functions that exist, and the exact compiler messages a mistake produces. Read this before writing GLSL for any target, and before believing an error message.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md7.6 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

GLSL fundamentals

GLSL is not one language. It is a family, and the first thing to get right is which member of it you are writing. A shader that is correct in one is a wall of errors in another, and the errors never say "wrong dialect".

The five dialects this row tells apart

dialectlooks likecompiles here
es100no #version, gl_FragColor, precisionyes - WebGL 1
es300#version 300 es, your own out vec4yes - WebGL 2
shadertoyvoid mainImage(out vec4, in vec2), no #versionyes - wrapped in ES 3.00
shader-skillssame as Shadertoy, but iFrame is an intyes - wrapped in ES 3.00
desktop#version 330 core and up, no esno - static checks only

shader_verify detects the dialect and says which one it found. Believe it, and if it guessed wrong, pass dialect explicitly.

Desktop GLSL is not WebGL GLSL

If a source starts with #version 330 core (or 110, 120, 150, 450), it is desktop GLSL. ANGLE - the compiler behind every browser - does not accept it. The row answers v1-static and names glslangValidator as the tool that would compile it. Three constructs mark the boundary, and each is a compile error on the wrong side:

#version 300 es
precision highp float;
out vec4 fragColor;
void main() { fragColor = vec4(1.0); }

That is a complete ES 3.00 fragment shader: it compiles as written. Its ES 1.00 twin is below - note gl_FragColor and the required precision statement.

precision highp float;
uniform float u_time;
void main() {
  float d = length(gl_FragCoord.xy / 256.0 - 0.5);
  gl_FragColor = vec4(vec3(smoothstep(0.4, 0.35, d)), 1.0);
}

gl_FragColor does not exist in #version 300 es. varying became in/out. texture2D became texture. attribute became in. Those four renames are most of what a "port to WebGL2" actually is.

Precision is not optional

A WebGL 1 fragment shader with no precision qualifier does not compile: ERROR: 0:1: '' : No precision specified for (float). Every es100 fragment starts with precision highp float; (or mediump). Vertex shaders have a default precision, which is why skipping it there works.

highp is what you want for coordinates and time; mediump is fine for colour and cheaper on mobile. Do not use highp inside a loop on hardware you have not tested - it is the first thing to drop for performance.

Types and the arithmetic traps

precision highp float;
float asFloat(int value) {
  return float(value);        // explicit conversion: `float x = 1;` is an error in ES 3.00
}
vec3 swapChannels(vec3 col) {
  col.rg = col.gr;            // swizzles assign in both directions
  return col;
}
mat2 rotate(float angle) {
  // mat2 is COLUMN-major: these four numbers are columns (a,b) and (c,d)
  return mat2(cos(angle), sin(angle), -sin(angle), cos(angle));
}
void main() {
  vec2 p = rotate(0.5) * (gl_FragCoord.xy / 64.0 - 0.5);
  gl_FragColor = vec4(swapChannels(vec3(p, asFloat(1))), 1.0);
}

A statement may not sit at global scope in GLSL: only declarations and functions can, and a global initialiser must be a constant expression. That is why the conversions above live inside functions.

The two errors that most often cost an hour:

  • dimension mismatch - a vec3 assigned to a float, or vec3(1.0) passed to a float parameter. The message is precise; read the two types it names.
  • no matching overloaded function found - the function exists but not for those argument types. min(1.0, 2) fails because there is no min(float, int).

Functions that are always there

sin cos tan asin acos atan pow exp log exp2 log2 sqrt inversesqrt abs sign floor ceil fract mod min max clamp mix step smoothstep length distance dot cross normalize reflect refract faceforward vec2 vec3 vec4 mat2 mat3 mat4 float int bool texture textureLod (ES 3.00) / texture2D (ES 1.00).

atan(y, x) - two arguments - is how you get an angle without losing the quadrant. mod(x, 1.0) repeats, but fract(x) is cheaper and identical for positive input. smoothstep(edge0, edge1, x) needs edge0 < edge1 or it is undefined: to invert a ramp, use 1.0 - smoothstep(a, b, x).

Loops and branches

In GLSL ES 1.00 the specification requires a constant loop bound:

precision highp float;
void main() {
  float sum = 0.0;
  for (int i = 0; i < 8; i++) {   // literal 8: always fine
    sum += 0.125;
  }
  gl_FragColor = vec4(vec3(sum), 1.0);
}

for (int i = 0; i < u_steps; i++) compiles on ANGLE and may fail on a mobile driver. If the count must vary, write a constant bound and break on the uniform. shader_verify warns about this (loop-bound), because the compiler here will not.

Branches are allowed but a branch that halves the work is often slower than mix(): prefer arithmetic over divergence in a fragment shader.

Derivatives need an extension in ES 1.00

fwidth, dFdx and dFdy are screen-space derivatives. In WebGL 1 they require gl.getExtension('OES_standard_derivatives') before the shader is compiled, otherwise the error is misleading:

WARNING: 0:1: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:108: 'fwidth' : no matching overloaded function found

It says the extension is unsupported when the real problem is that nobody asked for it. This row enables it for its own compiles; a page that embeds the shader must do the same. In ES 3.00 no extension is needed.

The uniform contract this row uses

Every wrapper dialect (shadertoy, shader-skills, module) is given:

uniformtypemeaning
u_timefloatseconds since start
u_resolutionvec2drawing buffer size in pixels
u_mousevec2pointer position in pixels
u_framefloatframe counter

Shadertoy names are provided too: iResolution (vec3), iTime, iTimeDelta, iFrameRate, iMouse (vec4) and iChannel0..3. iFrame is a float in Shadertoy and an int in the shader-skills corpus - which is why those are two dialects here. A function taking int rejects a float iFrame, and the error is no matching overloaded function found at the call site.

Parameters

Declare a tunable value on its own comment line; the tab turns it into a slider and every emitted page sets it:

// @param SPEED float 0.1..2.0 default 0.6 "Rotation speed"
precision highp float;
uniform float u_time;
uniform float u_speed;
void main() {
  float d = length(gl_FragCoord.xy / 256.0 - 0.5);
  gl_FragColor = vec4(vec3(0.5 + 0.5 * sin(d * 30.0 - u_time * u_speed)), 1.0);
}

The uniform name is u_ plus the lower-cased parameter name: SPEED -> u_speed. The source must declare it, or lint warns param-uniform.

Check yourself before you claim it works

shader_verify answers with a rung, and only these count:

  • v1-static - the rules above ran. No compiler did. Say so.
  • v2-compiled - a real compiler accepted it, on your line numbers.
  • v3-drawn - a frame was actually drawn and the pixels came back.
  • v4-measured - two different times drew differently.

A shader is not "working" at v1. If you are on a machine with no browser, say that the compile did not happen instead of implying it did.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Author an editorial HTML+SVG diagram with the Diagram Design kit - choose the visual type, read its reference, start from an example, and satisfy the safety and accessibility contract that diagram_write({kind:"html"}) enforces.

The English summary is being prepared. Showing the original description.

vecnode/vn-code10Updated Oct 20, 2026

Control this machine's Docker or Podman engine through the docker_* tools - read the engine's state first, list containers and images, inspect one, tail its logs, pull an image and start it, then stop, restart or remove what you started. Covers the engine that is asleep behind Docker Desktop and the exact call for each verb, the confirm rule removals obey, and the flags the tools deliberately do not have.

The English summary is being prepared. Showing the original description.

vecnode/vn-code10Updated Oct 20, 2026

Drive ffmpeg through the media_run tool as an argv array - remux instead of re-encode, map streams explicitly, trim at keyframes, scale and crop, extract audio and frames, and build GIFs, contact sheets and concatenations. Covers the flags this pack injects, reading a failure from its exit code and last log lines, and the version-dependent spellings to hedge.

The English summary is being prepared. Showing the original description.

vecnode/vn-code10Updated Oct 20, 2026

Read a media file's real structure with ffprobe through media_run - the JSON invocation and how to read it, what every family of field means, how to count frames, sample without decoding everything, detect HDR and interlacing, and diagnose a missing duration, a stream with no frames or a container that lies. Covers when media_probe's own report is already enough.

The English summary is being prepared. Showing the original description.

vecnode/vn-code10Updated Oct 20, 2026

Writing a fragment shader that looks like something - the full-screen triangle, uv space, signed distance fields, noise and fbm, domain warping, raymarching budgets, tone mapping and banding. Every example compiles. Read this when the task is "make it look good", not "make it compile".

The English summary is being prepared. Showing the original description.

vecnode/vn-code10Updated Oct 20, 2026

Use when the user wants to design, redesign, shape, critique, audit, polish, simplify, harden, animate, or otherwise improve a frontend interface: websites, landing pages, dashboards, product UI, components, forms, settings, onboarding, empty states, and native iOS or Android screens. Handles UX review, hierarchy, layout, typography, color, motion, UX copy, accessibility, responsive behavior, edge cases, and capturing or documenting design systems (DESIGN.md, tokens). Also for making bland UI bolder, loud UI quieter, or ambitious visual effects. Not for backend-only or non-UI tasks.

The English summary is being prepared. Showing the original description.

vecnode/vn-code10Updated Oct 20, 2026

See all skills by vecnode

Report a problem with this skill