// CRTPipeline – PostFX pipeline that simulates a classic CRT monitor: // - Barrel distortion (curved screen edges) // - Scanlines (every other row darkened) // - Vignette (edge darkening) const fragShader = ` precision mediump float; uniform sampler2D uMainSampler; uniform vec2 uResolution; varying vec2 outTexCoord; void main (void) { // --- Screen curvature (barrel distortion) --- // Remap UV from [0,1] to centred [-0.5,0.5], distort, remap back vec2 uv = outTexCoord; vec2 dc = uv - 0.5; float strength = 0.18; uv = uv + dc * dot(dc, dc) * strength; // Pixels pushed outside [0,1] become black (the CRT bezel) if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; } // --- Base colour --- vec4 color = texture2D(uMainSampler, uv); // --- Scanlines --- // Every other screen-pixel row is darkened by ~28% float lineY = uv.y * uResolution.y; float scanline = mod(floor(lineY), 2.0); color.rgb *= mix(1.0, 0.72, scanline); // --- Vignette --- float vig = 1.4 - dot(dc * 1.8, dc * 1.8); vig = clamp(vig, 0.0, 1.0); vig = pow(vig, 0.45); color.rgb *= vig; gl_FragColor = color; } `; export default class CRTPipeline extends Phaser.Renderer.WebGL.Pipelines.PostFXPipeline { constructor(game) { super({ game, name: 'CRTPipeline', fragShader }); } onPreRender() { this.set2f('uResolution', this.game.scale.width, this.game.scale.height); } }