Shader code
shader_type canvas_item;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
// --- UPDATED AESTHETIC PARAMETERS ---
uniform float color_levels : hint_range(2.0, 128.0) = 14.0;
uniform float chromatic_aberration : hint_range(0.0, 0.2) = 0.008;
uniform float blur_amount : hint_range(0.0, 5.0) = 1.0;
uniform float brightness : hint_range(0.5, 3.0) = 1.2;
uniform float saturation : hint_range(1.0, 5.0) = 1.0;
// --- UPDATED GLITCH PARAMETERS ---
uniform float color_offset_multiplier: hint_range(0.0, 0.2) = 0.004;
uniform float black_offset_multiplier: hint_range(0.0, 0.5) = 0.1;
uniform float color_offset: hint_range(-0.1, 0.1) = 0.005;
// Noise function
float noise(vec2 uv, float offset) {
return (fract(sin(dot(uv * offset, vec2(12.9898, 78.233))) * 43758.5453) - 0.5) * 2.0;
}
vec3 rgb_to_yuv(vec3 rgb) {
const mat3 RGB_TO_YUV = mat3(vec3(0.299, 0.587, 0.114), vec3(-0.14713, -0.28886, 0.436), vec3(.615, -0.51499, -0.10001));
return rgb * RGB_TO_YUV;
}
vec3 yuv_to_rgb(vec3 yuv) {
const mat3 YUV_TO_RGB = mat3(vec3(1.0, 0.0, 1.13983), vec3(1.0, -0.39465, -0.58060), vec3(1.0, 2.03211, 0.0));
return clamp(yuv * YUV_TO_RGB, vec3(0.0), vec3(1.0));
}
void fragment() {
vec2 uv = SCREEN_UV;
// 1. MOVEMENT LOGIC
float line_logic = uv.y * 487.0;
vec2 noise_coord = vec2(floor(line_logic), fract(line_logic));
float x_offset = color_offset + noise(noise_coord, TIME) * color_offset_multiplier;
float black_offset = noise(noise_coord, TIME + 65.0) * (black_offset_multiplier * 0.01);
// 2. SAMPLING
vec3 col;
col.r = texture(SCREEN_TEXTURE, uv + vec2(chromatic_aberration + black_offset, 0.0)).r;
col.g = texture(SCREEN_TEXTURE, uv + vec2(black_offset, 0.0)).g;
col.b = texture(SCREEN_TEXTURE, uv - vec2(chromatic_aberration - black_offset, 0.0)).b;
// 3. YUV CHROMATIC SHIFT
vec4 color_shifted = textureLod(SCREEN_TEXTURE, uv + vec2(x_offset, 0.0), blur_amount * 0.25);
vec3 yuv_base = rgb_to_yuv(col);
vec3 yuv_chroma = rgb_to_yuv(color_shifted.rgb);
col = yuv_to_rgb(vec3(yuv_base.x, yuv_chroma.yz));
// 4. POST-PROCESSING EFFECTS
float luma = dot(col, vec3(0.299, 0.587, 0.114));
col = mix(vec3(luma), col, saturation);
col *= brightness;
// Posterization
col.rgb = floor(col.rgb * color_levels + 0.3) / color_levels;
// --- VIGNETTE REMOVED ---
// Final pushed contrast
col = clamp(col, 0.0, 1.0);
col = mix(col, col * col * (3.0 - 2.0 * col), 0.6);
COLOR = vec4(col, 1.0);
}
Live Preview
Tags
horror,
VHS
DOOOOPE ! Thank you <3. We will use it as our in game shader, that was excatly what I was searching for!
Check us for some ideas of the rendering 😉
https://store.steampowered.com/app/3756600/Dungeon_Cleaners/
(demo in january 2026)
Thank you! <3 I’m glad the shader was exactly what you were looking for.
I’ll definitely check out your game, best of luck with the development!
Get the game: https://rot-7.itch.io/lullaby