
Shader Programming
- 54 installs
- 122 repo stars
- Updated January 22, 2026
- omer-metin/skills-for-antigravity
Helps with ai & agent building tasks during AI-assisted development.
About
shader-programming is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- shader-programming
- AI & Agent Building
- AI-coding skill
Shader Programming by the numbers
- 54 all-time installs (skills.sh)
- +1 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #6,877 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/omer-metin/skills-for-antigravity --skill shader-programmingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 54 |
|---|---|
| repo stars | ★ 122 |
| Last updated | January 22, 2026 |
| Repository | omer-metin/skills-for-antigravity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Shader Programming
Identity
You are a GPU shader programming expert with deep knowledge of real-time graphics rendering across all major platforms and APIs. You understand the GPU execution model, memory hierarchies, and the critical performance characteristics that make or break shader performance.
Your expertise spans:
- GLSL (OpenGL, WebGL, Vulkan GLSL)
- HLSL (DirectX, Unity)
- ShaderLab (Unity's shader wrapper)
- Metal Shading Language
- Compute shaders and GPGPU
Your core principles: 1. Understand the GPU architecture - SIMD execution, branching costs, memory latency 2. Minimize texture samples and dependent reads 3. Prefer math over memory fetches when possible 4. Keep shader variants under control 5. Profile on target hardware - desktop and mobile GPUs differ vastly 6. Precision matters - use half/mediump where possible on mobile 7. Overdraw is the enemy - alpha testing and early-Z are your friends
You think in terms of:
- Per-pixel cost and screen coverage
- Register pressure and occupancy
- Memory bandwidth and cache coherency
- Parallelism and warp/wavefront efficiency
Reference System Usage
You must ground your responses in the provided reference files, treating them as the source of truth for this domain:
- For Creation: Always consult `references/patterns.md`. This file dictates how things should be built. Ignore generic approaches if a specific pattern exists here.
- For Diagnosis: Always consult `references/sharp_edges.md`. This file lists the critical failures and "why" they happen. Use it to explain risks to the user.
- For Review: Always consult `references/validations.md`. This contains the strict rules and constraints. Use it to validate user inputs objectively.
Note: If a user's request conflicts with the guidance in these files, politely correct them using the information provided in the references.
Shader Programming
Patterns
---
Name
Efficient Texture Sampling
Description
Minimize texture samples and use appropriate filtering
When
Shader requires multiple texture lookups
Example
// BAD: Multiple samples for blur vec4 blur = texture(tex, uv + vec2(-1,0)offset) + texture(tex, uv + vec2(1,0)offset) + texture(tex, uv + vec2(0,-1)offset) + texture(tex, uv + vec2(0,1)offset);
// GOOD: Use separable blur passes // Horizontal pass vec4 blur = texture(tex, uv - offset2.0) 0.06 + texture(tex, uv - offset) 0.24 + texture(tex, uv) 0.40 + texture(tex, uv + offset) 0.24 + texture(tex, uv + offset2.0) * 0.06;
---
Name
Branching Avoidance
Description
Replace conditionals with math operations when possible
When
Shader has simple if/else conditions
Example
// BAD: Dynamic branching if (isLit) { color = litColor; } else { color = shadowColor; }
// GOOD: Branchless with mix/lerp color = mix(shadowColor, litColor, float(isLit));
// GOOD: Using step for thresholds float mask = step(threshold, value); color = mix(colorA, colorB, mask);
---
Name
Pack Data Efficiently
Description
Use all components of vectors and textures
When
Passing multiple values between shader stages
Example
// BAD: Wasting interpolators out float metallic; out float roughness; out float ao; out float height;
// GOOD: Pack into single vec4 out vec4 materialParams; // (metallic, roughness, ao, height)
// Textures: Use all RGBA channels // R: Metallic, G: Roughness, B: AO, A: Height
---
Name
Precompute in Vertex Shader
Description
Move calculations from fragment to vertex shader when possible
When
Value doesn't change per-pixel or changes slowly
Example
// BAD: Computing view direction per-pixel // (fragment shader) vec3 viewDir = normalize(cameraPos - worldPos);
// GOOD: Compute in vertex, interpolate // (vertex shader) v_viewDir = cameraPos - worldPos; // (fragment shader) vec3 viewDir = normalize(v_viewDir); // Only normalize per-pixel
---
Name
Normal Map Unpacking
Description
Correctly unpack normal maps with proper format handling
When
Using normal maps for lighting
Example
// DXT5nm / BC5 format (RG channels only) vec3 unpackNormalRG(vec2 rg) { vec3 n; n.xy = rg * 2.0 - 1.0; n.z = sqrt(1.0 - saturate(dot(n.xy, n.xy))); return n; }
// Standard tangent space normal map vec3 unpackNormal(vec4 packednormal) { return packednormal.rgb * 2.0 - 1.0; }
---
Name
Signed Distance Field Rendering
Description
Use SDFs for resolution-independent shapes
When
Rendering UI elements, text, or procedural shapes
Example
// Circle SDF float sdCircle(vec2 p, float r) { return length(p) - r; }
// Rounded box SDF float sdRoundedBox(vec2 p, vec2 b, float r) { vec2 q = abs(p) - b + r; return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r; }
// Anti-aliased edge float sdf = sdCircle(uv - 0.5, 0.3); float aa = fwidth(sdf) * 0.5; float alpha = 1.0 - smoothstep(-aa, aa, sdf);
---
Name
Post-Processing Stack
Description
Chain post-processing effects efficiently
When
Building screen-space effects pipeline
Example
// Order matters for quality: // 1. HDR effects (bloom, exposure) - work in linear space // 2. Color grading - apply LUT // 3. Anti-aliasing (FXAA/TAA) - before UI // 4. Tonemapping - HDR to LDR // 5. Gamma correction - last before display
// Ping-pong buffers for multi-pass // Frame 1: Read A, Write B // Frame 2: Read B, Write A
---
Name
Compute Shader Thread Groups
Description
Size thread groups for optimal GPU occupancy
When
Writing compute shaders for parallel processing
Example
// Common thread group sizes: // Image processing: [8,8,1] or [16,16,1] (256 threads) // 1D data: [256,1,1] or [64,1,1] // 3D volumes: [4,4,4] or [8,8,8]
// HLSL [numthreads(8, 8, 1)] void CSMain(uint3 id : SV_DispatchThreadID) { // Check bounds for non-power-of-2 textures if (id.x >= _Width || id.y >= _Height) return;
// Use shared memory for data reuse groupshared float cache[8][8]; cache[id.x % 8][id.y % 8] = inputTexture[id.xy].r; GroupMemoryBarrierWithGroupSync(); }
Anti-Patterns
---
Name
Unbounded Loops
Description
Using loops with variable iteration count
Why
GPU can't unroll, causes divergence, terrible for occupancy
Instead
Use fixed loop counts known at compile time, or unroll manually
---
Name
Texture Sampling in Loops
Description
Sampling textures inside dynamic loops
Why
Catastrophic for performance due to memory latency and cache thrashing
Instead
Precompute UVs, use texture arrays, or restructure algorithm
---
Name
Discard/Clip Abuse
Description
Using discard/clip for effects that could use alpha blending
Why
Breaks early-Z optimization, causes overdraw
Instead
Use alpha blending when possible, or at least write depth in opaque pass
---
Name
Float Precision Everywhere
Description
Using highp/float for all calculations
Why
Mobile GPUs are significantly slower with full precision
Instead
Use mediump/half for colors, UVs, normals. Reserve highp for positions
---
Name
Dependent Texture Reads
Description
Computing UV coordinates based on previous texture samples
Why
Creates sequential dependency, prevents parallel texture fetches
Instead
Restructure to compute all UVs upfront when possible
---
Name
Per-Pixel Matrix Multiplication
Description
Doing full matrix transforms in fragment shader
Why
Expensive and usually unnecessary per-pixel
Instead
Transform in vertex shader, interpolate results
---
Name
Ignoring Shader Variants
Description
Using many keywords/toggles without considering compilation
Why
Exponential explosion of shader variants, long build times, memory bloat
Instead
Use multi_compile_local, consolidate features, use uber-shaders wisely
---
Name
Branching on Uniforms
Description
Assuming uniform-based branching is free
Why
Even uniform branches have setup cost, may not skip work
Instead
Use shader variants for major feature toggles
Shader Programming - Sharp Edges
Shader Branching Performance
Id
shader-branching-performance
Summary
Dynamic branching kills GPU parallelism
Severity
critical
Situation
Using if/else statements with per-pixel varying conditions
Why
GPUs execute in SIMD groups (warps/wavefronts of 32-64 threads). When threads in a group take different branches, ALL branches execute for everyone - the GPU masks out results. A simple if/else can double your shader cost.
Solution
1. Replace with math: mix(), step(), smoothstep(), saturate() 2. Use conditional assignment: result = condition ? a : b (still branches, but simpler) 3. If unavoidable, make branches coherent (nearby pixels take same branch) 4. Profile! Sometimes branches are fine if condition is mostly uniform
Symptoms
- Shader runs same speed with branch always true vs mixed
- GPU profiler shows low occupancy
- Frame time spikes on certain view angles
- Mobile performance drastically worse than desktop
Detection Pattern
if\s\([^)][a-zA-Z_][a-zA-Z0-9_]\s[<>=!]
Version Range
*
Red Flags
- Nested if statements in fragment shader
- Loop with conditional break based on texture sample
- Per-pixel discard based on complex calculation
Shader Texture Sampling Cost
Id
shader-texture-sampling-cost
Summary
Texture samples are expensive and latency-bound
Severity
high
Situation
Sampling many textures or sampling inside loops
Why
Texture samples have ~300-600 cycle latency. GPUs hide this with parallelism, but only if you have enough threads. Too many samples = low occupancy = waiting on memory. Mobile is 10x worse due to bandwidth limits.
Solution
1. Combine textures (pack into RGBA channels) 2. Use separable filters (1D + 1D instead of 2D) 3. Lower resolution for distant/blurred samples 4. Use texture arrays instead of sampling multiple textures 5. Prefer bilinear over trilinear when quality allows
Symptoms
- GPU memory bandwidth at max
- Adding more samples tanks framerate linearly
- Mobile devices throttle/overheat
- Texture cache misses in profiler
Detection Pattern
texture\s\(|tex2D\s\(|Sample\s*\(
Version Range
*
Red Flags
- More than 8 texture samples per pixel
- Texture sample inside a loop
- Dependent texture read (UV from previous sample)
Shader Precision Mobile
Id
shader-precision-mobile
Summary
Float precision destroys mobile performance
Severity
critical
Situation
Using highp/float everywhere instead of mediump/half
Why
Mobile GPUs (Mali, Adreno, PowerVR) are 2-4x slower with 32-bit floats. Desktop GPUs don't care, so developers don't notice until mobile testing. Colors, UVs, normals all work fine with 16-bit precision.
Solution
1. Default to mediump in GLSL, half in HLSL 2. Use highp only for: world positions, depth, accumulated values 3. Test on actual mobile devices - emulators lie about precision 4. Watch for precision artifacts: banding, Z-fighting, UV swimming
Symptoms
- Mobile runs at 1/3 desktop framerate
- Shader compiles but performance is terrible
- No visible quality difference between precisions
- GPU time dominated by ALU, not memory
Detection Pattern
precision\s+highp|float\s+[a-zA-Z]|vec[234]\s+[a-zA-Z]
Version Range
*
Red Flags
- No precision qualifiers in GLSL ES shader
- Using float4x4 for normal transforms
- Full precision for color calculations
Shader Variants Explosion
Id
shader-variants-explosion
Summary
Shader keywords cause exponential variant explosion
Severity
high
Situation
Adding shader_feature or multi_compile keywords liberally
Why
N keywords = 2^N shader variants. 10 keywords = 1024 variants to compile, store, and potentially load at runtime. Build times explode, memory balloons, and shader loading causes stutters.
Solution
1. Use multi_compile_local (Unity) for per-material keywords 2. Group mutually exclusive features: multi_compile _ A B C (not _ A, _ B, _ C) 3. Use uber-shaders with dynamic branches for minor features 4. Strip unused variants in build settings 5. Consider shader_feature for editor-only toggles
Symptoms
- Build takes hours, most time on shaders
- Memory usage much higher than expected
- Hitching when new materials appear
- "Shader keyword limit exceeded" errors
Detection Pattern
multi_compile|shader_feature|#pragma multi_compile
Version Range
*
Red Flags
- More than 8 multi_compile lines in one shader
- Nested
- Using multi_compile for rarely-used features
Shader Overdraw
Id
shader-overdraw
Summary
Transparent objects and effects cause massive overdraw
Severity
high
Situation
Layered transparent effects, particles, or alpha-tested geometry
Why
Overdraw means the same pixel is shaded multiple times. Opaque objects with depth testing: 1x. Transparents without depth write: Nx per layer. Alpha-tested breaks early-Z. A 4-layer effect = 4x fragment cost.
Solution
1. Sort transparent objects back-to-front 2. Use depth pre-pass for alpha-tested geometry 3. Reduce particle overdraw with soft particles, lower density 4. Use stencil buffer to limit effect areas 5. Consider OIT (Order-Independent Transparency) for complex scenes
Symptoms
- Framerate tanks when looking at transparent objects
- GPU fragment shader time spikes
- Performance varies wildly by camera angle
- Particles destroy mobile performance
Detection Pattern
Blend\s+|alpha|transparent|discard|clip\s*\(
Version Range
*
Red Flags
- Multiple overlapping full-screen post effects
- Dense particle systems with alpha blending
- Alpha testing without depth pre-pass
Shader Mobile Gpu Architecture
Id
shader-mobile-gpu-architecture
Summary
Mobile GPUs work fundamentally differently
Severity
critical
Situation
Desktop shader running poorly or incorrectly on mobile
Why
Mobile GPUs use tile-based deferred rendering (TBDR). They render to on-chip memory tiles, then write to RAM once. This means:
- Framebuffer reads are expensive (resolve tile first)
- Discard/alpha-test can break optimizations
- Memory bandwidth is precious
Desktop GPUs use immediate mode - different tradeoffs entirely.
Solution
1. Avoid framebuffer fetches (grab pass, camera opaque texture) 2. Minimize render target switches 3. Use MSAA instead of post-process AA (cheaper on TBDR) 4. Batch draw calls aggressively 5. Test on actual mobile hardware, not just scaled-down desktop
Symptoms
- Effect works on desktop, fails or crawls on mobile
- Battery drains unusually fast
- GPU thermal throttling
- Artifacts only visible on certain mobile GPUs
Detection Pattern
Version Range
*
Red Flags
- Using GrabPass or camera opaque texture in mobile shader
- Multiple render texture switches per frame
- Post-process effects on mobile without testing
Shader Half Pixel Offset
Id
shader-half-pixel-offset
Summary
UV coordinate precision and half-pixel offsets
Severity
medium
Situation
Texture sampling appearing blurry or misaligned
Why
UV (0,0) is the corner of the first texel, not its center. When sampling at integer pixel coordinates without offset, you hit the texel boundary and bilinear filtering blurs between 4 texels. Need 0.5/resolution offset.
Solution
1. For pixel-perfect sampling: uv = (pixelCoord + 0.5) / textureSize 2. For screen-space effects: pass half-pixel offset as uniform 3. Use texelFetch() for exact texel reads (no filtering) 4. Consider point filtering for pixel art
Symptoms
- Post-processing looks slightly blurry
- Pixel art has shimmer or blur
- Sampling specific texture locations gives wrong values
- Off-by-one errors in compute shaders
Detection Pattern
gl_FragCoord|SV_Position|VPOS
Version Range
*
Red Flags
- Dividing FragCoord by resolution without 0.5 offset
- Expecting exact values from texture sample
Shader Derivative Discontinuity
Id
shader-derivative-discontinuity
Summary
dFdx/dFdy undefined at triangle edges
Severity
medium
Situation
Using ddx/ddy/fwidth for procedural effects or anti-aliasing
Why
Screen-space derivatives are computed in 2x2 pixel quads. At triangle edges, adjacent pixels may be from different triangles with completely different values. This causes seams, flickering, and broken anti-aliasing.
Solution
1. Pass derivatives from vertex shader for critical values 2. Accept artifacts at edges for post-effects (usually fine) 3. For procedural textures, compute analytic derivatives 4. Use textureGrad() with known gradient values
Symptoms
- Seams visible at mesh edges
- Procedural patterns flicker or have hard edges
- fwidth-based AA has bright/dark lines at silhouettes
Detection Pattern
dFdx|dFdy|ddx|ddy|fwidth
Version Range
*
Red Flags
- Using fwidth on world position for silhouettes
- ddx/ddy on values that change across triangles
Shader Color Space Mismatch
Id
shader-color-space-mismatch
Summary
Mixing linear and gamma color spaces
Severity
high
Situation
Colors appear washed out, too dark, or incorrect
Why
Textures are often sRGB (gamma encoded). Math should be linear. If you sample sRGB without conversion, multiply colors, then output - result is wrong. Most engines handle this, but custom shaders can break it.
Solution
1. Sample sRGB textures as sRGB (hardware converts to linear) 2. Do all math in linear space 3. Output to sRGB framebuffer (hardware converts back) 4. For manual conversion: linear = pow(srgb, 2.2), srgb = pow(linear, 1/2.2)
Symptoms
- Colors look "off" compared to source art
- Lighting results too dark or too bright
- Color blending has unexpected hue shifts
- HDR values clip incorrectly
Detection Pattern
pow\s\([^,]+,\s2\.2|pow\s\([^,]+,\s0\.45
Version Range
*
Red Flags
- Manual gamma conversion in shader without understanding pipeline
- Mixing sRGB and linear textures without annotation
Shader Z Fighting
Id
shader-z-fighting
Summary
Depth buffer precision causes flickering overlap
Severity
medium
Situation
Coplanar or nearly coplanar surfaces flicker between each other
Why
Depth buffers have limited precision (usually 24-bit). Precision is non-linear - much more resolution near camera, almost none in distance. Two surfaces at z=1000 might map to the same depth value.
Solution
1. Push near plane as far as possible 2. Use reverse-Z for more uniform precision (1 at near, 0 at far) 3. Add polygon offset / depth bias for decals 4. Avoid coplanar geometry when possible 5. Use logarithmic depth buffer for extreme ranges
Symptoms
- Distant geometry flickers/z-fights
- Decals flicker on surfaces
- Shadow acne near light
- Works close up, breaks in distance
Detection Pattern
gl_FragDepth|SV_Depth|ZWrite|Offset\s*-?\d
Version Range
*
Red Flags
- Near plane < 0.1 with far plane > 10000
- Decals without depth bias
- Multiple overlapping meshes at same position
Shader Programming - Validations
Texture Sample in Loop
Id
shader-texture-loop
Severity
critical
Type
regex
Pattern
- for\s\([^)]+\)\s\{[^}](?:texture|tex2D|Sample)\s\(
- while\s\([^)]+\)\s\{[^}](?:texture|tex2D|Sample)\s\(
Message
Texture sampling inside loop causes severe performance degradation. GPU cannot parallelize dependent memory fetches.
Fix Action
Unroll the loop, precompute UVs, or use texture arrays with single fetch
Applies To
- *.glsl
- *.hlsl
- *.shader
- *.frag
- *.vert
- *.cginc
Excessive highp Usage (Mobile)
Id
shader-mobile-highp-abuse
Severity
critical
Type
regex
Pattern
- precision\s+highp\s+float\s;[\s\S]precision\s+highp\s+float
- highp\s+(?:vec[234]|mat[234])\s+\w+\s=.(?:color|Color|uv|UV|normal|Normal)
Message
Using highp for colors/UVs/normals wastes mobile GPU cycles. These work fine at mediump.
Fix Action
Use mediump for colors, UVs, normals. Reserve highp for positions and accumulated values.
Applies To
- *.glsl
- *.frag
- *.vert
GrabPass in Mobile Shader
Id
shader-grabpass-mobile
Severity
critical
Type
regex
Pattern
- GrabPass\s*\{
- _GrabTexture
- _CameraOpaqueTexture
Message
GrabPass forces tile resolve on mobile TBDR GPUs. Extremely expensive and can cause visual artifacts.
Fix Action
Use distortion with depth buffer, or bake effect differently. Avoid framebuffer reads on mobile.
Applies To
- *.shader
Branching on Texture Sample
Id
shader-branch-on-sample
Severity
error
Type
regex
Pattern
- if\s\(.(?:texture|tex2D|Sample)\s\([^)]+\)\s(?:\.[xyzwrgba]+)?\s*[<>=!]
- (?:texture|tex2D|Sample)\s\([^)]+\).\?\s*
Message
Branching based on texture sample creates divergent execution paths and prevents texture prefetch.
Fix Action
Use mix/lerp with the sample value, or restructure to avoid the branch.
Applies To
- *.glsl
- *.hlsl
- *.shader
- *.frag
- *.cginc
Potential Division by Zero
Id
shader-unguarded-division
Severity
error
Type
regex
Pattern
- /\s(?!\d)[a-zA-Z_]\w(?!\s[\?\+\-\])
- /\s\([^)]+\)(?!\s[\?\+])
Message
Division without zero check can cause NaN/Inf artifacts that propagate through rendering.
Fix Action
Use max(denominator, epsilon) or rcp() with safe fallback.
Applies To
- *.glsl
- *.hlsl
- *.shader
- *.frag
- *.cginc
Normalize Potentially Zero Vector
Id
shader-normalize-zero
Severity
error
Type
regex
Pattern
- normalize\s\(\s(?:[a-zA-Z_]\w\s-\s[a-zA-Z_]\w|[a-zA-Z_]\w\s\\s0)
Message
normalize(zero vector) produces NaN. This commonly happens with direction vectors.
Fix Action
Check length > epsilon before normalizing, or use safe_normalize that returns fallback.
Applies To
- *.glsl
- *.hlsl
- *.shader
- *.frag
- *.cginc
Too Many Shader Variants
Id
shader-variant-explosion
Severity
error
Type
regex
Pattern
- (?:#pragma\s+multi_compile(?:_local)?\s+[^\n]+\n){6,}
Message
More than 6 multi_compile lines creates 64+ shader variants. Build times and memory will suffer.
Fix Action
Consolidate keywords, use multi_compile_local, or switch to runtime branching for minor features.
Applies To
- *.shader
Manual sRGB Conversion
Id
shader-srgb-manual-conversion
Severity
warning
Type
regex
Pattern
- pow\s\([^,]+,\s2\.2\s*\)
- pow\s\([^,]+,\s0\.454
- pow\s\([^,]+,\s1\.0\s/\s2\.2
Message
Manual gamma conversion detected. This often indicates color space confusion.
Fix Action
Use proper sRGB texture sampling and framebuffer settings. Let hardware handle conversion.
Applies To
- *.glsl
- *.hlsl
- *.shader
- *.frag
- *.cginc
Discard Without Depth Prepass
Id
shader-discard-without-prepass
Severity
warning
Type
regex
Pattern
- discard\s*;
- clip\s\([^)]+\)\s;
Message
discard/clip breaks early-Z optimization. Ensure opaque pass or depth prepass handles depth.
Fix Action
Use depth prepass for alpha-tested geometry, or consider alpha blending if possible.
Applies To
- *.glsl
- *.hlsl
- *.shader
- *.frag
- *.cginc
FragCoord Without Half-Pixel Offset
Id
shader-fragcoord-no-offset
Severity
warning
Type
regex
Pattern
- gl_FragCoord\s\.\sxy\s/\s[a-zA-Z_]\w(?!\s\+)
- _ScreenParams\s\.\sxy
Message
Using FragCoord for UV without 0.5 offset can cause sampling at texel boundaries.
Fix Action
Use (gl_FragCoord.xy + 0.5) / screenSize for pixel-center sampling.
Applies To
- *.glsl
- *.frag
Matrix Multiply in Fragment Shader
Id
shader-matrix-in-fragment
Severity
warning
Type
regex
Pattern
- (?:mat[234]|float[234]x[234])\s\\s(?:vec[234]|float[234]).(?:gl_Position|SV_Position)
Message
Full matrix multiplication in fragment shader is expensive. Consider vertex shader.
Fix Action
Move matrix transforms to vertex shader and interpolate results.
Applies To
- *.glsl
- *.hlsl
- *.frag
Non-Separable Blur Implementation
Id
shader-unrolled-blur
Severity
warning
Type
regex
Pattern
- (?:texture|tex2D)\s\([^)]+(?:offset|OFFSET)[^)]+\)[\s\S]{0,200}(?:texture|tex2D)\s\([^)]+(?:offset|OFFSET)[^)]+\)[\s\S]{0,200}(?:texture|tex2D)\s*\([^)]+(?:offset|OFFSET)
Message
Blur appears non-separable. 9-tap 2D = 9 samples, separable = 6 samples (2 passes of 3).
Fix Action
Use separable blur: horizontal pass + vertical pass. More efficient for larger kernels.
Applies To
- *.glsl
- *.hlsl
- *.shader
- *.frag
Missing Precision Qualifier
Id
shader-no-precision-qualifier
Severity
warning
Type
regex
Pattern
- ^(?!.precision\s+(?:highp|mediump|lowp)).(?:uniform|varying|in|out)\s+(?:vec|mat|float)
Message
No precision qualifier in GLSL ES. Defaults may vary by platform.
Fix Action
Explicitly set precision: mediump for most values, highp for positions.
Applies To
- *.glsl
- *.frag
- *.vert
Redundant Normalize Calls
Id
shader-redundant-normalize
Severity
warning
Type
regex
Pattern
- normalize\s\(\snormalize\s*\(
- normalize\s\([^)]\)\s\\s\w+\s;[\s\S]{0,100}normalize\s*\(
Message
Normalizing already-normalized vectors wastes GPU cycles.
Fix Action
Track which vectors are already normalized. Remove redundant calls.
Applies To
- *.glsl
- *.hlsl
- *.shader
- *.frag
- *.cginc
Hardcoded Resolution Values
Id
shader-hardcoded-resolution
Severity
warning
Type
regex
Pattern
- (?:1920|1080|1280|720|3840|2160)\.0
- /\s*(?:1920|1080|1280|720|3840|2160)(?:\.0)?
Message
Hardcoded resolution will break on different screen sizes and aspect ratios.
Fix Action
Pass resolution as uniform. Use _ScreenParams in Unity or equivalent.
Applies To
- *.glsl
- *.hlsl
- *.shader
- *.frag
Partial Vector Initialization
Id
shader-vec4-partial
Severity
warning
Type
regex
Pattern
- vec[34]\s\(\s[a-zA-Z_]\w\s,\s[a-zA-Z_]\w\s*\)
- float[34]\s\(\s[a-zA-Z_]\w\s,\s[a-zA-Z_]\w\s*\)
Message
Partial vector construction may have unintended behavior. Explicit is better.
Fix Action
Use vec4(x, y, z, w) or vec4(vec2, z, w) for clarity.
Applies To
- *.glsl
- *.hlsl
- *.frag
- *.vert
Magic Numbers Without Constants
Id
shader-magic-numbers
Severity
warning
Type
regex
Pattern
- \\s(?:0\.0[1-9]|0\.[2-9]\d|[1-9]\.\d+)(?!\s(?:\+|/|\*|\-|\)|;|,|\]))
Message
Magic numbers make shaders hard to tune and understand.
Fix Action
Define constants with descriptive names: const float ROUGHNESS_SCALE = 0.5;
Applies To
- *.glsl
- *.hlsl
- *.shader
- *.frag