True, but it’s worth mentioning that most CRTs oversaturate red a lot when playing video games over composite or RF, which causes the electron gun bleed to increase compared to RGB or YPbPr component.
About the chroma lowpass/bandpass which NTSC shaders already kind of do, the “right way” to do them is to simulate the lowpass/bandpass that’s found in the schematics of the actual console and CRT. That’s how to get that blur to go to the right instead of symmetrical. There must be some way to simulate this quickly and efficiently, but I haven’t tried yet myself.
As said before, the electron gun bleed is different.
so it mixed of both, classic analog 
One of the reasons I wrote this is not just to simulate/emulate faulty CRT monitors, but because I know that even working monitors have these effects, albeit to a lesser extent. Therefore, I believe they are necessary to achieve the authentic experience, of course in small and reasonable proportions that don’t negatively affect the image
You just need to use an IIR filter as opposed to an FIR filter.
Recent test:
Added Grade, CRT Contrast +60%
(Color) Saturation 1.20
I think this is good but I don’t know why I have to do things to Saturation and Contrast- the difficulty here is that I’m not sure what’s expected.
shaders = "21"
feedback_pass = "0"
shader0 = "shaders_slang/p68k-fast-multipass-2025-11-07/p68k-fast-mp-pre-color-only.slang"
alias0 = ""
wrap_mode0 = "clamp_to_border"
mipmap_input0 = "false"
filter_linear0 = "false"
frame_count_mod0 = "2"
float_framebuffer0 = "true"
srgb_framebuffer0 = "false"
scale_type_x0 = "source"
scale_x0 = "1.000000"
scale_type_y0 = "source"
scale_y0 = "1.000000"
shader1 = "shaders_slang/p68k-fast-multipass-2025-11-07/p68k-fast-mp-post-color-only.slang"
alias1 = ""
wrap_mode1 = "clamp_to_border"
mipmap_input1 = "false"
filter_linear1 = "false"
frame_count_mod1 = "2"
float_framebuffer1 = "true"
srgb_framebuffer1 = "false"
scale_type_x1 = "source"
scale_x1 = "1.000000"
scale_type_y1 = "source"
scale_y1 = "1.000000"
shader2 = "shaders_slang/misc/shaders/grade-no-LUT.slang"
alias2 = ""
wrap_mode2 = "clamp_to_border"
mipmap_input2 = "false"
float_framebuffer2 = "false"
srgb_framebuffer2 = "false"
scale_type_x2 = "viewport"
scale_x2 = "1.000000"
scale_type_y2 = "viewport"
scale_y2 = "1.000000"
shader3 = "shaders_slang/crt/shaders/guest/advanced/stock.slang"
alias3 = ""
wrap_mode3 = "clamp_to_border"
mipmap_input3 = "false"
filter_linear3 = "false"
float_framebuffer3 = "false"
srgb_framebuffer3 = "false"
scale_type_x3 = "source"
scale_x3 = "1.000000"
scale_type_y3 = "source"
scale_y3 = "1.000000"
shader4 = "shaders_slang/crt/shaders/guest/advanced/stock.slang"
alias4 = "StockPass"
wrap_mode4 = "clamp_to_border"
mipmap_input4 = "false"
filter_linear4 = "false"
float_framebuffer4 = "false"
srgb_framebuffer4 = "false"
scale_type_x4 = "source"
scale_x4 = "1.000000"
scale_type_y4 = "source"
scale_y4 = "1.000000"
shader5 = "shaders_slang/crt/shaders/guest/advanced/afterglow0.slang"
alias5 = "AfterglowPass"
wrap_mode5 = "clamp_to_border"
mipmap_input5 = "false"
filter_linear5 = "true"
float_framebuffer5 = "false"
srgb_framebuffer5 = "false"
scale_type_x5 = "source"
scale_x5 = "1.000000"
scale_type_y5 = "source"
scale_y5 = "1.000000"
shader6 = "shaders_slang/crt/shaders/guest/advanced/pre-shaders-afterglow.slang"
alias6 = "PrePass0"
wrap_mode6 = "clamp_to_border"
mipmap_input6 = "false"
filter_linear6 = "true"
float_framebuffer6 = "false"
srgb_framebuffer6 = "false"
scale_type_x6 = "source"
scale_x6 = "1.000000"
scale_type_y6 = "source"
scale_y6 = "1.000000"
shader7 = "shaders_slang/crt/shaders/guest/advanced/ntsc/ntsc-pass1.slang"
alias7 = "NPass1"
wrap_mode7 = "clamp_to_border"
mipmap_input7 = "false"
filter_linear7 = "false"
float_framebuffer7 = "true"
srgb_framebuffer7 = "false"
scale_type_x7 = "source"
scale_x7 = "4.000000"
scale_type_y7 = "source"
scale_y7 = "1.000000"
shader8 = "shaders_slang/crt/shaders/guest/advanced/ntsc/ntsc-pass2.slang"
alias8 = ""
wrap_mode8 = "clamp_to_border"
mipmap_input8 = "false"
filter_linear8 = "true"
float_framebuffer8 = "true"
srgb_framebuffer8 = "false"
scale_type_x8 = "source"
scale_x8 = "0.500000"
scale_type_y8 = "source"
scale_y8 = "1.000000"
shader9 = "shaders_slang/crt/shaders/guest/advanced/ntsc/ntsc-pass3.slang"
alias9 = ""
wrap_mode9 = "clamp_to_border"
mipmap_input9 = "false"
filter_linear9 = "true"
float_framebuffer9 = "false"
srgb_framebuffer9 = "false"
scale_type_x9 = "source"
scale_x9 = "1.000000"
scale_type_y9 = "source"
scale_y9 = "1.000000"
shader10 = "shaders_slang/crt/shaders/guest/advanced/custom-fast-sharpen.slang"
alias10 = "NtscPass"
wrap_mode10 = "clamp_to_border"
mipmap_input10 = "false"
filter_linear10 = "true"
float_framebuffer10 = "false"
srgb_framebuffer10 = "false"
scale_type_x10 = "source"
scale_x10 = "1.000000"
scale_type_y10 = "source"
scale_y10 = "1.000000"
shader11 = "shaders_slang/crt/shaders/guest/advanced/stock.slang"
alias11 = "PrePass"
wrap_mode11 = "clamp_to_border"
mipmap_input11 = "true"
filter_linear11 = "true"
float_framebuffer11 = "false"
srgb_framebuffer11 = "false"
scale_type_x11 = "source"
scale_x11 = "1.000000"
scale_type_y11 = "source"
scale_y11 = "1.000000"
shader12 = "shaders_slang/crt/shaders/guest/advanced/avg-lum-ntsc.slang"
alias12 = "AvgLumPass"
wrap_mode12 = "clamp_to_border"
mipmap_input12 = "true"
filter_linear12 = "true"
float_framebuffer12 = "false"
srgb_framebuffer12 = "false"
scale_type_x12 = "source"
scale_x12 = "1.000000"
scale_type_y12 = "source"
scale_y12 = "1.000000"
shader13 = "shaders_slang/crt/shaders/guest/advanced/linearize-ntsc.slang"
alias13 = "LinearizePass"
wrap_mode13 = "clamp_to_border"
mipmap_input13 = "false"
filter_linear13 = "true"
float_framebuffer13 = "true"
srgb_framebuffer13 = "false"
scale_type_x13 = "source"
scale_x13 = "1.000000"
scale_type_y13 = "source"
scale_y13 = "1.000000"
shader14 = "shaders_slang/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass1.slang"
alias14 = "Pass1"
wrap_mode14 = "clamp_to_border"
mipmap_input14 = "false"
filter_linear14 = "true"
float_framebuffer14 = "true"
srgb_framebuffer14 = "false"
scale_type_x14 = "viewport"
scale_x14 = "1.000000"
scale_type_y14 = "source"
scale_y14 = "1.000000"
shader15 = "shaders_slang/crt/shaders/guest/hd/gaussian_horizontal.slang"
alias15 = ""
wrap_mode15 = "clamp_to_border"
mipmap_input15 = "false"
filter_linear15 = "true"
float_framebuffer15 = "true"
srgb_framebuffer15 = "false"
scale_type_x15 = "absolute"
scale_x15 = "800"
scale_type_y15 = "source"
scale_y15 = "1.000000"
shader16 = "shaders_slang/crt/shaders/guest/advanced/gaussian_vertical.slang"
alias16 = "GlowPass"
wrap_mode16 = "clamp_to_border"
mipmap_input16 = "false"
filter_linear16 = "true"
float_framebuffer16 = "true"
srgb_framebuffer16 = "false"
scale_type_x16 = "absolute"
scale_x16 = "800"
scale_type_y16 = "absolute"
scale_y16 = "600"
shader17 = "shaders_slang/crt/shaders/guest/hd/bloom_horizontal.slang"
alias17 = ""
wrap_mode17 = "clamp_to_border"
mipmap_input17 = "false"
filter_linear17 = "true"
float_framebuffer17 = "true"
srgb_framebuffer17 = "false"
scale_type_x17 = "absolute"
scale_x17 = "800"
scale_type_y17 = "absolute"
scale_y17 = "600"
shader18 = "shaders_slang/crt/shaders/guest/advanced/bloom_vertical.slang"
alias18 = "BloomPass"
wrap_mode18 = "clamp_to_border"
mipmap_input18 = "false"
filter_linear18 = "true"
float_framebuffer18 = "true"
srgb_framebuffer18 = "false"
scale_type_x18 = "absolute"
scale_x18 = "800"
scale_type_y18 = "absolute"
scale_y18 = "600"
shader19 = "shaders_slang/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass2.slang"
alias19 = ""
wrap_mode19 = "clamp_to_border"
mipmap_input19 = "false"
filter_linear19 = "true"
float_framebuffer19 = "true"
srgb_framebuffer19 = "false"
scale_type_x19 = "viewport"
scale_x19 = "1.000000"
scale_type_y19 = "viewport"
scale_y19 = "1.000000"
shader20 = "shaders_slang/crt/shaders/guest/advanced/deconvergence-ntsc.slang"
alias20 = ""
wrap_mode20 = "clamp_to_border"
mipmap_input20 = "false"
filter_linear20 = "true"
float_framebuffer20 = "false"
srgb_framebuffer20 = "false"
scale_type_x20 = "viewport"
scale_x20 = "1.000000"
scale_type_y20 = "viewport"
scale_y20 = "1.000000"
pfm_stdApproxGamma = "3.000000"
pf_gamma = "1.999996"
pf_color = "1.200000"
pf_hdr_enable = "2.000000"
g_CRT_l = "2.600000"
g_CRT_c = "80.000000"
wlr = "1.020000"
gr = "0.020000"
br = "0.020000"
cust_artifacting = "0.000000"
cust_fringing = "0.000000"
ntsc_scale = "1.500000"
ntsc_taps = "6.000000"
GAMMA_INPUT = "2.200000"
gamma_out = "2.200000"
m_glow = "2.000000"
glow = "0.020000"
brightboost = "1.000000"
brightboost1 = "1.000000"
gsl = "2.000000"
scanline1 = "5.000000"
scanline2 = "35.000000"
beam_min = "1.200000"
beam_size = "0.000000"
scans = "1.000000"
shadowMask = "12.000000"
maskstr = "0.800000"
mcut = "1.000000"
post_br = "1.500000"
textures = "SamplerLUT1;SamplerLUT2;SamplerLUT3;SamplerLUT4"
SamplerLUT1 = "shaders_slang/crt/shaders/guest/advanced/lut/trinitron-lut.png"
SamplerLUT1_mipmap = "false"
SamplerLUT1_wrap_mode = "clamp_to_border"
SamplerLUT2 = "shaders_slang/crt/shaders/guest/advanced/lut/inv-trinitron-lut.png"
SamplerLUT2_mipmap = "false"
SamplerLUT2_wrap_mode = "clamp_to_border"
SamplerLUT3 = "shaders_slang/crt/shaders/guest/advanced/lut/nec-lut.png"
SamplerLUT3_mipmap = "false"
SamplerLUT3_wrap_mode = "clamp_to_border"
SamplerLUT4 = "shaders_slang/crt/shaders/guest/advanced/lut/ntsc-lut.png"
SamplerLUT4_mipmap = "false"
SamplerLUT4_wrap_mode = "clamp_to_border"
And here’s another with no grade, default settings for guest-advanced. I have no idea what changed. Using the version from “p68k-fast-multipass-2025-11-07”
Edit: It seems to be only the ntsc colors preset that’s working, the others all result in the washed out image
shaders = "21"
feedback_pass = "0"
shader0 = "shaders_slang/p68k-fast-multipass-2025-11-07/p68k-fast-mp-pre-color-only.slang"
alias0 = ""
wrap_mode0 = "clamp_to_border"
mipmap_input0 = "false"
filter_linear0 = "false"
frame_count_mod0 = "2"
float_framebuffer0 = "true"
srgb_framebuffer0 = "false"
scale_type_x0 = "source"
scale_x0 = "1.000000"
scale_type_y0 = "source"
scale_y0 = "1.000000"
shader1 = "shaders_slang/p68k-fast-multipass-2025-11-07/p68k-fast-mp-post-color-only.slang"
alias1 = ""
wrap_mode1 = "clamp_to_border"
mipmap_input1 = "false"
filter_linear1 = "false"
frame_count_mod1 = "2"
float_framebuffer1 = "true"
srgb_framebuffer1 = "false"
scale_type_x1 = "source"
scale_x1 = "1.000000"
scale_type_y1 = "source"
scale_y1 = "1.000000"
shader2 = "shaders_slang/stock.slang"
alias2 = ""
wrap_mode2 = "clamp_to_border"
mipmap_input2 = "false"
float_framebuffer2 = "false"
srgb_framebuffer2 = "false"
scale_type_x2 = "viewport"
scale_x2 = "1.000000"
scale_type_y2 = "viewport"
scale_y2 = "1.000000"
shader3 = "shaders_slang/crt/shaders/guest/advanced/stock.slang"
alias3 = ""
wrap_mode3 = "clamp_to_border"
mipmap_input3 = "false"
filter_linear3 = "false"
float_framebuffer3 = "false"
srgb_framebuffer3 = "false"
scale_type_x3 = "source"
scale_x3 = "1.000000"
scale_type_y3 = "source"
scale_y3 = "1.000000"
shader4 = "shaders_slang/crt/shaders/guest/advanced/stock.slang"
alias4 = "StockPass"
wrap_mode4 = "clamp_to_border"
mipmap_input4 = "false"
filter_linear4 = "false"
float_framebuffer4 = "false"
srgb_framebuffer4 = "false"
scale_type_x4 = "source"
scale_x4 = "1.000000"
scale_type_y4 = "source"
scale_y4 = "1.000000"
shader5 = "shaders_slang/crt/shaders/guest/advanced/afterglow0.slang"
alias5 = "AfterglowPass"
wrap_mode5 = "clamp_to_border"
mipmap_input5 = "false"
filter_linear5 = "true"
float_framebuffer5 = "false"
srgb_framebuffer5 = "false"
scale_type_x5 = "source"
scale_x5 = "1.000000"
scale_type_y5 = "source"
scale_y5 = "1.000000"
shader6 = "shaders_slang/crt/shaders/guest/advanced/pre-shaders-afterglow.slang"
alias6 = "PrePass0"
wrap_mode6 = "clamp_to_border"
mipmap_input6 = "false"
filter_linear6 = "true"
float_framebuffer6 = "false"
srgb_framebuffer6 = "false"
scale_type_x6 = "source"
scale_x6 = "1.000000"
scale_type_y6 = "source"
scale_y6 = "1.000000"
shader7 = "shaders_slang/crt/shaders/guest/advanced/ntsc/ntsc-pass1.slang"
alias7 = "NPass1"
wrap_mode7 = "clamp_to_border"
mipmap_input7 = "false"
filter_linear7 = "false"
float_framebuffer7 = "true"
srgb_framebuffer7 = "false"
scale_type_x7 = "source"
scale_x7 = "4.000000"
scale_type_y7 = "source"
scale_y7 = "1.000000"
shader8 = "shaders_slang/crt/shaders/guest/advanced/ntsc/ntsc-pass2.slang"
alias8 = ""
wrap_mode8 = "clamp_to_border"
mipmap_input8 = "false"
filter_linear8 = "true"
float_framebuffer8 = "true"
srgb_framebuffer8 = "false"
scale_type_x8 = "source"
scale_x8 = "0.500000"
scale_type_y8 = "source"
scale_y8 = "1.000000"
shader9 = "shaders_slang/crt/shaders/guest/advanced/ntsc/ntsc-pass3.slang"
alias9 = ""
wrap_mode9 = "clamp_to_border"
mipmap_input9 = "false"
filter_linear9 = "true"
float_framebuffer9 = "false"
srgb_framebuffer9 = "false"
scale_type_x9 = "source"
scale_x9 = "1.000000"
scale_type_y9 = "source"
scale_y9 = "1.000000"
shader10 = "shaders_slang/crt/shaders/guest/advanced/custom-fast-sharpen.slang"
alias10 = "NtscPass"
wrap_mode10 = "clamp_to_border"
mipmap_input10 = "false"
filter_linear10 = "true"
float_framebuffer10 = "false"
srgb_framebuffer10 = "false"
scale_type_x10 = "source"
scale_x10 = "1.000000"
scale_type_y10 = "source"
scale_y10 = "1.000000"
shader11 = "shaders_slang/crt/shaders/guest/advanced/stock.slang"
alias11 = "PrePass"
wrap_mode11 = "clamp_to_border"
mipmap_input11 = "true"
filter_linear11 = "true"
float_framebuffer11 = "false"
srgb_framebuffer11 = "false"
scale_type_x11 = "source"
scale_x11 = "1.000000"
scale_type_y11 = "source"
scale_y11 = "1.000000"
shader12 = "shaders_slang/crt/shaders/guest/advanced/avg-lum-ntsc.slang"
alias12 = "AvgLumPass"
wrap_mode12 = "clamp_to_border"
mipmap_input12 = "true"
filter_linear12 = "true"
float_framebuffer12 = "false"
srgb_framebuffer12 = "false"
scale_type_x12 = "source"
scale_x12 = "1.000000"
scale_type_y12 = "source"
scale_y12 = "1.000000"
shader13 = "shaders_slang/crt/shaders/guest/advanced/linearize-ntsc.slang"
alias13 = "LinearizePass"
wrap_mode13 = "clamp_to_border"
mipmap_input13 = "false"
filter_linear13 = "true"
float_framebuffer13 = "true"
srgb_framebuffer13 = "false"
scale_type_x13 = "source"
scale_x13 = "1.000000"
scale_type_y13 = "source"
scale_y13 = "1.000000"
shader14 = "shaders_slang/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass1.slang"
alias14 = "Pass1"
wrap_mode14 = "clamp_to_border"
mipmap_input14 = "false"
filter_linear14 = "true"
float_framebuffer14 = "true"
srgb_framebuffer14 = "false"
scale_type_x14 = "viewport"
scale_x14 = "1.000000"
scale_type_y14 = "source"
scale_y14 = "1.000000"
shader15 = "shaders_slang/crt/shaders/guest/hd/gaussian_horizontal.slang"
alias15 = ""
wrap_mode15 = "clamp_to_border"
mipmap_input15 = "false"
filter_linear15 = "true"
float_framebuffer15 = "true"
srgb_framebuffer15 = "false"
scale_type_x15 = "absolute"
scale_x15 = "800"
scale_type_y15 = "source"
scale_y15 = "1.000000"
shader16 = "shaders_slang/crt/shaders/guest/advanced/gaussian_vertical.slang"
alias16 = "GlowPass"
wrap_mode16 = "clamp_to_border"
mipmap_input16 = "false"
filter_linear16 = "true"
float_framebuffer16 = "true"
srgb_framebuffer16 = "false"
scale_type_x16 = "absolute"
scale_x16 = "800"
scale_type_y16 = "absolute"
scale_y16 = "600"
shader17 = "shaders_slang/crt/shaders/guest/hd/bloom_horizontal.slang"
alias17 = ""
wrap_mode17 = "clamp_to_border"
mipmap_input17 = "false"
filter_linear17 = "true"
float_framebuffer17 = "true"
srgb_framebuffer17 = "false"
scale_type_x17 = "absolute"
scale_x17 = "800"
scale_type_y17 = "absolute"
scale_y17 = "600"
shader18 = "shaders_slang/crt/shaders/guest/advanced/bloom_vertical.slang"
alias18 = "BloomPass"
wrap_mode18 = "clamp_to_border"
mipmap_input18 = "false"
filter_linear18 = "true"
float_framebuffer18 = "true"
srgb_framebuffer18 = "false"
scale_type_x18 = "absolute"
scale_x18 = "800"
scale_type_y18 = "absolute"
scale_y18 = "600"
shader19 = "shaders_slang/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass2.slang"
alias19 = ""
wrap_mode19 = "clamp_to_border"
mipmap_input19 = "false"
filter_linear19 = "true"
float_framebuffer19 = "true"
srgb_framebuffer19 = "false"
scale_type_x19 = "viewport"
scale_x19 = "1.000000"
scale_type_y19 = "viewport"
scale_y19 = "1.000000"
shader20 = "shaders_slang/crt/shaders/guest/advanced/deconvergence-ntsc.slang"
alias20 = ""
wrap_mode20 = "clamp_to_border"
mipmap_input20 = "false"
filter_linear20 = "true"
float_framebuffer20 = "false"
srgb_framebuffer20 = "false"
scale_type_x20 = "viewport"
scale_x20 = "1.000000"
scale_type_y20 = "viewport"
scale_y20 = "1.000000"
pf_hdr_enable = "2.000000"
textures = "SamplerLUT1;SamplerLUT2;SamplerLUT3;SamplerLUT4"
SamplerLUT1 = "shaders_slang/crt/shaders/guest/advanced/lut/trinitron-lut.png"
SamplerLUT1_mipmap = "false"
SamplerLUT1_wrap_mode = "clamp_to_border"
SamplerLUT2 = "shaders_slang/crt/shaders/guest/advanced/lut/inv-trinitron-lut.png"
SamplerLUT2_mipmap = "false"
SamplerLUT2_wrap_mode = "clamp_to_border"
SamplerLUT3 = "shaders_slang/crt/shaders/guest/advanced/lut/nec-lut.png"
SamplerLUT3_mipmap = "false"
SamplerLUT3_wrap_mode = "clamp_to_border"
SamplerLUT4 = "shaders_slang/crt/shaders/guest/advanced/lut/ntsc-lut.png"
SamplerLUT4_mipmap = "false"
SamplerLUT4_wrap_mode = "clamp_to_border"
@PlainOldPants apologies if you already discussed this somewhere but I was wondering if you have done gamut analysis on more modern TV color enhancement features like on an LCD. It would be interesting if it is at all related to what consumer CRT TVs are doing with color.
I have not done that sort of analysis on any modern displays yet. I have a couple modern TV sets, which don’t have great image quality, but I seldom use them. They’re mainly used by other family members that I live with.
At least, I have tried playing around with settings. I was able to turn off a couple settings that had been “enhancing” the image by oversaturating it and causing details to get clamped and disappear. One thing that stuck out to me was that an LG set had a “Dynamic Color” feature that could be set to Off, Low, Mid, or High, and it was keeping colors near the red/yellow/green boundary in place while moving other colors towards blue. I might try to get pictures of this, and maybe get rough measurements with the X-Rite i1Display 2.
As for now, I don’t have the time to be working on anything here, but I’ve been checking on these forums every once in a while. I have too many other things going on.