CRT Filter

The key words MUST, MUST NOT, MAY, and REQUIRED below are used as in RFC 2119.

An optional full-screen post-process that makes the game look like it is being played on a CRT. It is purely cosmetic: it MUST NOT change gameplay, timing, input, or any value the game reads back — it only changes what reaches the glass.

Modes

The setting is a three-state cycle, not a boolean. Off is the default.

Scope — what goes through the tube

The filter treats the composited frame. The 3D world, every HUD canvas, the start menu, and the SceneManager fade MUST all pass through it — a UI layer floating crisp and unwarped above a curved image gives the illusion away. Concretely, the overlay MUST sit above every other CanvasLayer in the project (today: layer 260, above the fade at 250).

Curvature MUST NOT crop

Barrel distortion pushes the corners of the image outside the sampled area. Rather than let that clip content, the warp MUST be rescaled by exactly its own corner factor, so the corners land back on the frame edge. No pixel that the game drew is lost — which matters because the HP/PP panel, the minimap and the action palette all live in corners.

The cost of that guarantee is a thin black band at the middles of the edges, which reads as the tube's bezel. Full therefore keeps its curvature small; a larger value would trade a wider bezel for a bulge nobody asked for.

Resolution independence

Scanlines are counted against a fixed virtual line count (240), not against physical pixels, so the look is identical at 720p and at 4K instead of the lines dissolving into the pixel grid on a large display. The aperture grille is the opposite: it is measured in physical pixels (3px RGB triads), because a grille is meant to be a fine texture, not a visible stripe pattern that scales up with the window.

Persistence

The mode persists to user://video_settings.cfg under [video] crt_mode, as one of the string ids off / scanlines / full. It is stored as a string rather than an enum ordinal so that reordering the modes can never silently reinterpret a saved config as a different filter.

This is a video setting, so it belongs to the machine, not to the character: it MUST NOT ride along with SaveManager.save_game() and MUST survive deleting or switching characters. An unrecognised crt_mode id (hand-edited, or written by a build with a different mode set) MUST fall back to Off.

Where it is suppressed

Implemented by

The shader file MUST stay under res://scripts/. It is reachable from an autoload, and autoloads must compile before the asset pack mounts — see the compile contract in Field Stage Lifecycle.