Best Practices & Style
39.1 Code style
Always specify #version and the profile; enable only the extensions you need.
Consistent naming: a prefix for attributes (aPos), v for varyings (vNormal), u for uniforms (uTime), o/out for outputs, UPPER_CASE macros and constants.
Use explicit layout(location/binding) qualifiers — removes host-side lookups and mismatches.
Write floats as floats (1.0, not 1) — required in GLSL ES.
Keep functions small and reusable (lighting.glsl, noise.glsl); comment coordinate spaces (// world space).
Normalize interpolated vectors in the fragment shader.
Use const for compile-time constants; make loop bounds constant where possible.
Format with clang-format (works reasonably for GLSL) and validate with glslangValidator in CI.
39.2 Correctness checklist
Every vector used in dot/reflect is normalized when it should be.
All lighting vectors are in the same space (world or view).
Color textures are sRGB; data textures are linear; output is gamma-encoded exactly once.
HDR values are tone-mapped before display.
No reads of uninitialized variables; outputs written on all paths.
No pow(negative, y), sqrt(negative), normalize(vec3(0)), division by zero, acos outside [-1, 1] (clamp first).
Texture sampling with derivatives happens in uniform control flow.
Buffer layouts (std140/std430) match host structs exactly.
Integer varyings are flat.
Precision qualifiers are adequate on mobile.
39.3 Performance checklist
Profile before optimizing; know whether you're vertex, fragment, bandwidth, or CPU bound.
Reduce overdraw and full-screen passes; render expensive effects at lower resolution.
Use texture compression, mipmaps, and channel packing.
Batch, instance, and use indirect drawing.
Prefer compute shaders for data-parallel work that doesn't need rasterization.
Cache compiled programs/pipelines; avoid compiling shaders mid-frame (stutter).