From godot-claude-skills
Writes Godot 4.x shaders (.gdshader files) for 2D canvas_item effects, 3D spatial materials, particles, sky, fog, and post-processing. Covers uniforms, hints, structure, and built-in variables.
npx claudepluginhub alexmeckes/godot-claude-skills --plugin godot-claude-skillsThis skill uses the workspace's default tool permissions.
You are an expert at writing Godot 4.x shaders (.gdshader files) for 2D effects, 3D materials, and post-processing.
Implements Godot 4.3+ shaders: canvas_item for 2D effects, spatial for 3D materials, particles, sky, fog; covers GLSL-like language basics, creation, and visual recipes.
Generates ShaderToy-compatible GLSL shaders for ray marching, SDF scenes, fluid sims, particles, procedural noise, lighting, and post-processing effects via WebGL2 HTML pages.
Provides GLSL ES syntax reference, Shadertoy conventions, built-in inputs, coordinate patterns, and techniques for fragment shaders, procedural graphics, and WebGL effects.
Share bugs, ideas, or general feedback.
You are an expert at writing Godot 4.x shaders (.gdshader files) for 2D effects, 3D materials, and post-processing.
shader_type canvas_item; // 2D sprites, UI, CanvasItem nodes
shader_type spatial; // 3D materials
shader_type particles; // GPU particle systems
shader_type sky; // Sky/environment
shader_type fog; // Volumetric fog
shader_type canvas_item;
// Render modes (optional)
render_mode unshaded, blend_mix;
// Uniforms (exposed to inspector)
uniform vec4 tint_color : source_color = vec4(1.0);
uniform float intensity : hint_range(0.0, 1.0) = 0.5;
uniform sampler2D noise_texture : hint_default_white;
// Varyings (pass data vertex -> fragment)
varying vec2 world_position;
void vertex() {
// Modify vertex position
world_position = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
}
void fragment() {
// Output color
vec4 tex_color = texture(TEXTURE, UV);
COLOR = tex_color * tint_color;
}
// Color picker in inspector
uniform vec4 color : source_color = vec4(1.0);
// Slider with range
uniform float value : hint_range(0.0, 1.0, 0.01) = 0.5;
// Texture hints
uniform sampler2D albedo_tex : source_color, filter_linear_mipmap;
uniform sampler2D normal_tex : hint_normal;
uniform sampler2D noise_tex : hint_default_white;
uniform sampler2D mask_tex : hint_default_black;
// Instance uniforms (per-instance values)
instance uniform vec4 instance_color : source_color = vec4(1.0);
// Vertex shader
VERTEX // vec2 - vertex position
UV // vec2 - texture coordinates
COLOR // vec4 - vertex color
POINT_SIZE // float - point size
// Fragment shader
UV // vec2 - interpolated UVs
SCREEN_UV // vec2 - screen space UVs
FRAGCOORD // vec4 - fragment coordinates
COLOR // vec4 - output color
NORMAL // vec3 - normal for 2D lighting
TEXTURE // sampler2D - sprite texture
TEXTURE_PIXEL_SIZE // vec2 - texel size
// Both
TIME // float - shader time
PI // float - 3.14159...
TAU // float - 6.28318...
// Vertex shader
VERTEX // vec3 - vertex position (local)
NORMAL // vec3 - vertex normal
UV // vec2 - primary UVs
UV2 // vec2 - secondary UVs
COLOR // vec4 - vertex color
POSITION // vec4 - clip space position (output)
// Fragment shader
ALBEDO // vec3 - base color (output)
ALPHA // float - transparency (output)
METALLIC // float - metalness (output)
ROUGHNESS // float - roughness (output)
EMISSION // vec3 - emissive color (output)
NORMAL_MAP // vec3 - normal map (output)
NORMAL_MAP_DEPTH // float - normal map strength
AO // float - ambient occlusion (output)
RIM // float - rim lighting (output)
RIM_TINT // float - rim tint amount
shader_type canvas_item;
uniform vec4 flash_color : source_color = vec4(1.0, 1.0, 1.0, 1.0);
uniform float flash_amount : hint_range(0.0, 1.0) = 0.0;
void fragment() {
vec4 tex_color = texture(TEXTURE, UV);
COLOR = mix(tex_color, flash_color, flash_amount);
COLOR.a = tex_color.a;
}
shader_type canvas_item;
uniform vec4 outline_color : source_color = vec4(0.0, 0.0, 0.0, 1.0);
uniform float outline_width : hint_range(0.0, 10.0) = 1.0;
void fragment() {
vec2 size = TEXTURE_PIXEL_SIZE * outline_width;
float outline = texture(TEXTURE, UV + vec2(-size.x, 0)).a;
outline += texture(TEXTURE, UV + vec2(size.x, 0)).a;
outline += texture(TEXTURE, UV + vec2(0, -size.y)).a;
outline += texture(TEXTURE, UV + vec2(0, size.y)).a;
outline = min(outline, 1.0);
vec4 tex_color = texture(TEXTURE, UV);
COLOR = mix(outline_color * outline, tex_color, tex_color.a);
}
shader_type canvas_item;
uniform sampler2D dissolve_texture : hint_default_white;
uniform float dissolve_amount : hint_range(0.0, 1.0) = 0.0;
uniform float edge_width : hint_range(0.0, 0.2) = 0.05;
uniform vec4 edge_color : source_color = vec4(1.0, 0.5, 0.0, 1.0);
void fragment() {
vec4 tex_color = texture(TEXTURE, UV);
float noise = texture(dissolve_texture, UV).r;
float edge = smoothstep(dissolve_amount, dissolve_amount + edge_width, noise);
float alpha = step(dissolve_amount, noise);
COLOR = mix(edge_color, tex_color, edge);
COLOR.a = tex_color.a * alpha;
}
shader_type canvas_item;
uniform float pixel_size : hint_range(1.0, 100.0) = 4.0;
void fragment() {
vec2 grid_uv = round(UV * pixel_size) / pixel_size;
COLOR = texture(TEXTURE, grid_uv);
}
shader_type canvas_item;
uniform float wave_amplitude : hint_range(0.0, 0.1) = 0.02;
uniform float wave_frequency : hint_range(0.0, 50.0) = 10.0;
uniform float wave_speed : hint_range(0.0, 10.0) = 2.0;
void fragment() {
vec2 uv = UV;
uv.x += sin(uv.y * wave_frequency + TIME * wave_speed) * wave_amplitude;
COLOR = texture(TEXTURE, uv);
}
shader_type canvas_item;
uniform sampler2D gradient : hint_default_white;
void fragment() {
vec4 tex_color = texture(TEXTURE, UV);
float luminance = dot(tex_color.rgb, vec3(0.299, 0.587, 0.114));
vec3 mapped = texture(gradient, vec2(luminance, 0.0)).rgb;
COLOR = vec4(mapped, tex_color.a);
}
shader_type canvas_item;
uniform float offset : hint_range(0.0, 0.01) = 0.005;
void fragment() {
vec2 dir = UV - vec2(0.5);
float r = texture(TEXTURE, UV + dir * offset).r;
float g = texture(TEXTURE, UV).g;
float b = texture(TEXTURE, UV - dir * offset).b;
float a = texture(TEXTURE, UV).a;
COLOR = vec4(r, g, b, a);
}
shader_type spatial;
uniform vec4 albedo_color : source_color = vec4(1.0);
uniform sampler2D albedo_texture : source_color, hint_default_white;
uniform float metallic : hint_range(0.0, 1.0) = 0.0;
uniform float roughness : hint_range(0.0, 1.0) = 0.5;
void fragment() {
vec4 tex = texture(albedo_texture, UV);
ALBEDO = tex.rgb * albedo_color.rgb;
METALLIC = metallic;
ROUGHNESS = roughness;
ALPHA = tex.a * albedo_color.a;
}
shader_type spatial;
uniform vec4 rim_color : source_color = vec4(1.0);
uniform float rim_power : hint_range(0.0, 10.0) = 3.0;
void fragment() {
float fresnel = pow(1.0 - dot(NORMAL, VIEW), rim_power);
EMISSION = rim_color.rgb * fresnel * rim_color.a;
}
shader_type spatial;
uniform sampler2D texture_albedo : source_color;
uniform float blend_sharpness : hint_range(1.0, 10.0) = 3.0;
varying vec3 world_position;
varying vec3 world_normal;
void vertex() {
world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
world_normal = (MODEL_MATRIX * vec4(NORMAL, 0.0)).xyz;
}
void fragment() {
vec3 blending = pow(abs(world_normal), vec3(blend_sharpness));
blending /= blending.x + blending.y + blending.z;
vec3 x_proj = texture(texture_albedo, world_position.yz).rgb;
vec3 y_proj = texture(texture_albedo, world_position.xz).rgb;
vec3 z_proj = texture(texture_albedo, world_position.xy).rgb;
ALBEDO = x_proj * blending.x + y_proj * blending.y + z_proj * blending.z;
}
shader_type spatial;
render_mode cull_disabled, depth_draw_opaque;
uniform vec4 hologram_color : source_color = vec4(0.0, 1.0, 1.0, 1.0);
uniform float scan_speed : hint_range(0.0, 10.0) = 2.0;
uniform float scan_line_count : hint_range(10.0, 200.0) = 50.0;
uniform float flicker_speed : hint_range(0.0, 20.0) = 5.0;
void fragment() {
float scan = sin((UV.y + TIME * scan_speed) * scan_line_count) * 0.5 + 0.5;
float flicker = sin(TIME * flicker_speed) * 0.1 + 0.9;
float fresnel = pow(1.0 - dot(NORMAL, VIEW), 2.0);
ALBEDO = hologram_color.rgb;
EMISSION = hologram_color.rgb * (scan * 0.5 + 0.5) * flicker;
ALPHA = (fresnel + 0.3) * scan * flicker * hologram_color.a;
}
Apply to ColorRect covering viewport:
shader_type canvas_item;
uniform float vignette_intensity : hint_range(0.0, 1.0) = 0.4;
uniform float vignette_opacity : hint_range(0.0, 1.0) = 0.5;
void fragment() {
vec4 color = texture(TEXTURE, UV);
float vignette = UV.x * UV.y * (1.0 - UV.x) * (1.0 - UV.y);
vignette = clamp(pow(16.0 * vignette, vignette_intensity), 0.0, 1.0);
color.rgb = mix(color.rgb, color.rgb * vignette, vignette_opacity);
COLOR = color;
}
shader_type canvas_item;
uniform float scanline_count : hint_range(0.0, 1000.0) = 400.0;
uniform float scanline_intensity : hint_range(0.0, 1.0) = 0.1;
uniform float curvature : hint_range(0.0, 0.1) = 0.02;
void fragment() {
// Barrel distortion
vec2 uv = UV - 0.5;
float dist = dot(uv, uv);
uv *= 1.0 + dist * curvature;
uv += 0.5;
vec4 color = texture(TEXTURE, uv);
// Scanlines
float scanline = sin(uv.y * scanline_count * PI) * 0.5 + 0.5;
color.rgb -= scanline_intensity * scanline;
// Edge fade
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
color = vec4(0.0);
}
COLOR = color;
}
shader_type particles;
uniform float spread : hint_range(0.0, 180.0) = 45.0;
uniform float initial_speed : hint_range(0.0, 100.0) = 10.0;
void start() {
float angle = radians(spread) * (RANDOM.x - 0.5);
vec3 direction = vec3(sin(angle), cos(angle), 0.0);
VELOCITY = direction * initial_speed;
}
void process() {
// Apply gravity
VELOCITY.y -= 9.8 * DELTA;
// Fade out
COLOR.a = 1.0 - LIFETIME;
// Scale down
TRANSFORM[0].x = 1.0 - LIFETIME * 0.5;
TRANSFORM[1].y = 1.0 - LIFETIME * 0.5;
}
hint_range, source_color make shaders usable