@@ -80,14 +80,12 @@ fn get_wave_dist(hist_idx: u32, uv: vec2<f32>, aspect: f32) -> f32 {
8080@fragment
8181fn fs_main (in : VertexOutput ) -> @location (0 ) vec4 <f32 > {
8282 // CRT barrel distortion
83- let crt_uv = in . uv * 2 .0 - 1 .0 ;
84- let r2 = dot (crt_uv , crt_uv );
85- let distorted_uv = crt_uv * (1 .0 + r2 * 0 .05 );
86- let final_uv = distorted_uv * 0 .5 + 0 .5 ;
83+ let final_uv = crt_distort_uv (in . uv , 0 .05 );
8784
88- let aspect = dpdx ( in . uv . x ) / dpdy ( in . uv . y ) ;
85+ let aspect = audio . aspect_ratio ;
8986 var final_color = vec3 <f32 >(0 .0 );
9087
88+ let crt_uv = in . uv * 2 .0 - 1 .0 ;
9189 let r = length (crt_uv );
9290 let edge_blur = smoothstep (0 .2 , 1 .5 , r );
9391
@@ -96,11 +94,20 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
9694
9795 var wave_intensity = 0 .0 ;
9896
97+ let dy = dpdy (in . uv . y );
98+ let base_thickness = max (dy * 0 .6 , 0 .0005 );
99+ let blur_thickness = max (dy * 2 .0 , 0 .0015 );
100+
99101 // Performance: skip every other history frame when count exceeds 72,
100102 // compensating with doubled contribution to maintain total brightness.
101103 let hist_count = min (audio . waveform_history_size , 144u );
102104 let step = select (1u , 2u , hist_count > 72u );
103105 let step_scale = f32 (step );
106+
107+ // Lock thickness to physical screen pixels so it doesn't vanish on short windows
108+ let thickness = base_thickness + edge_blur * blur_thickness ;
109+ // Tighter bloom (reduced spread and intensity)
110+ let bloom_spread = max (dy * 0 .2 , 0 .0002 );
104111
105112 for (var i = 0u ; i < hist_count ; i = i + step ) {
106113 let true_dist = get_wave_dist (i , final_uv , aspect );
@@ -111,12 +118,8 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
111118 // 0.05 gives a long 1-second smooth trail.
112119 let age = exp (- frames_old * 0 .06 );
113120
114- // Much thinner beam for crisp, high-resolution lines instead of thick noodles
115- let thickness = 0 .0005 + edge_blur * 0 .0015 ;
116121 let core = smoothstep (thickness , 0 .0 , true_dist ) * 0 .6 ;
117-
118- // Tighter bloom (reduced spread and intensity)
119- let bloom = 0 .00005 / (true_dist * true_dist + 0 .0002 ) * 0 .02 ;
122+ let bloom = 0 .00005 / (true_dist * true_dist + bloom_spread ) * 0 .02 ;
120123
121124 // Tighter halation (faster falloff)
122125 let halation = exp (- true_dist * 120 .0 ) * 0 .01 ;
@@ -130,24 +133,18 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
130133 let mapped = wave_intensity * amber ;
131134 var tonemapped = (mapped * (2 .51 * mapped + 0 .03 )) / (mapped * (2 .43 * mapped + 0 .59 ) + 0 .14 );
132135
133- final_color = tonemapped ;
134-
135- // CRT scanlines
136- let scanline = 0 .85 + 0 .15 * cos (in . clip_position . y * 3 .14159 );
137- final_color *= scanline ;
138-
136+ var crt_settings = get_default_crt ();
137+ crt_settings . phosphor_tint = amber ; // Not used as tint for everything, just to configure if needed. Actually we'll keep final_color.
138+
139139 // Smooth CRT bezel fade (radial, no rectangular edges)
140140 let bezel = smoothstep (1 .4 , 0 .9 , r );
141-
142- // Analog noise / static (like vis_flame)
143- let noise_val = hash21 (in . clip_position . xy + fract (audio . smooth_time ) * 137 .0 );
144- let static_noise = noise_val * 0 .035 * bezel ;
145141
146- // Add extra faint glow from the waveform onto the noise
142+ // Analog noise glow
143+ let noise_val = hash21_crt (in . clip_position . xy + fract (audio . smooth_time ) * 137 .0 );
147144 let noise_glow = amber * noise_val * 0 .015 * bezel * clamp (wave_intensity * 0 .8 , 0 .0 , 1 .0 );
148145
149- final_color = final_color * bezel ;
150- final_color = final_color + static_noise + noise_glow ;
146+ final_color = apply_crt_effects ( tonemapped , in . uv , in . clip_position . xy , audio . smooth_time , crt_settings ) ;
147+ final_color = final_color + noise_glow ;
151148
152149 // Output Linear RGB. WGPU Srgb surface will apply the sRGB gamma curve automatically.
153150 return vec4 <f32 >(final_color , 1 .0 );
0 commit comments