@group(0) @binding(0) var smplr: sampler; @group(0) @binding(1) var txt: texture_2d; struct CommonUniforms { resolution: vec2, aspect_ratio: f32, time: f32, beat: f32, audio_intensity: f32, }; struct EffectParams { offset_scale: f32, angle: f32, }; @group(0) @binding(2) var common: CommonUniforms; @group(0) @binding(3) var params: EffectParams; @vertex fn vs_main(@builtin(vertex_index) i: u32) -> @builtin(position) vec4 { var pos = array, 3>( vec2(-1, -1), vec2(3, -1), vec2(-1, 3) ); return vec4(pos[i], 0.0, 1.0); } @fragment fn fs_main(@builtin(position) p: vec4) -> @location(0) vec4 { let uv = p.xy / common.resolution; // Compute offset magnitude and direction let offset_mag = params.offset_scale * common.audio_intensity; let offset_dir = vec2(cos(params.angle), sin(params.angle)); let offset = offset_mag * offset_dir; // Sample RGB channels with chromatic aberration let r = textureSample(txt, smplr, uv + offset).r; let g = textureSample(txt, smplr, uv).g; let b = textureSample(txt, smplr, uv - offset).b; return vec4(r, g, b, 1.0); }