Custom Shaders

Apply a GLSL post-processing shader to the terminal for ricing, effects, or stylized rendering.

Wintty can run a custom shader after its default rendering pipeline. This is the same hook used by tools like Rxvt-Unicode background image filters or the WezTerm shader effect, scaled up to a Shadertoy-style API. You write a GLSL shader, point Wintty at it, and the shader gets a texture of the rendered terminal as input and produces the final pixels you see on screen.

This is a ricing feature first and foremost. Common uses are CRT scan lines, bloom, film grain, or subtle color grading. It's also useful for color blindness simulation and for shipping a recognizable aesthetic in screenshots.

Warning

An invalid shader can make Wintty unusable (for example, by painting the whole window black). If that happens, unset custom-shader in your config and reload to recover. Shader compile errors show up in the Wintty log, not in the configuration error list, because shaders are compiled on the render thread after config loading.

Configuring a Shader

Point custom-shader at a file path. The same option is repeatable, in which case the shaders run in order and the output of one becomes the input of the next:

custom-shader = C:\Users\you\shaders\crt.glsl
custom-shader = C:\Users\you\shaders\bloom.glsl

Relative paths are resolved against the configuration file's directory, so shaders/crt.glsl means a file next to your config. Tilde expansion is compiled out on Windows, so a path starting with ~/ is not expanded to your home directory. Use an absolute path or a config-relative one.

Wintty uses GLSL syntax for shaders. On Windows the shader is cross-compiled to the native shading language by the renderer, so you write GLSL even though Windows does not natively use OpenGL.

The shader must define a mainImage function with this signature, in the Shadertoy style:

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord.xy / iResolution.xy;
    fragColor = texture(iChannel0, uv);
}

iChannel0 is the rendered terminal. The above is a no-op pass-through.

Available Uniforms

The standard Shadertoy uniforms plus Wintty-specific extensions are available:

Shadertoy-style uniforms

UniformTypeDescription
iChannel0sampler2DThe current terminal screen (or the previous shader's output)
iResolutionvec3[width, height, 1] in pixels
iTimefloatSeconds since the first frame was rendered
iTimeDeltafloatSeconds since the previous frame
iFrameintFrame counter
iChannelResolution[0]vec3Same as iResolution (no extra channels are wired up)

iFrameRate, iChannelTime, iMouse, iDate, and iSampleRate are declared but not currently populated.

Wintty-specific uniforms

UniformTypeDescription
iCurrentCursorvec4Cursor position (xy) and size (zw)
iPreviousCursorvec4Cursor position and size on the previous frame
iCurrentCursorColorvec4RGBA cursor color
iPreviousCursorColorvec4Previous-frame cursor color
iCurrentCursorStyleintCursor style (block, bar, etc.)
iPreviousCursorStyleintPrevious-frame cursor style
iCursorVisibleint1 if the cursor is currently visible, 0 otherwise
iTimeCursorChangefloatiTime at the last cursor change
iTimeFocusfloatiTime at the last focus event
iFocusint1 if focused, 0 otherwise
iPalette[256]vec3The full 256-color terminal palette
iBackgroundColorvec3Configured background color
iForegroundColorvec3Configured foreground color
iCursorColorvec3Configured cursor color
iCursorTextvec3Configured cursor text color
iSelectionBackgroundColorvec3Selection background color
iSelectionForegroundColorvec3Selection foreground color

The cursor style is an int macro:

#define CURSORSTYLE_BLOCK        0
#define CURSORSTYLE_BLOCK_HOLLOW 1
#define CURSORSTYLE_BAR          2
#define CURSORSTYLE_UNDERLINE    3
#define CURSORSTYLE_LOCK         4

This lets you build effects keyed to cursor changes, focus changes, or the configured palette without hardcoding values.

Animation Cost

A purely static post-process shader (no iTime dependency) is basically free: it runs once per frame anyway. Animated shaders are more expensive because Wintty has to render continuously even when the terminal contents haven't changed.

custom-shader-animation controls when the animation loop runs:

ValueBehavior
true (default)Animate only when the focused terminal uses custom shaders
falseOnly redraw on terminal updates (no animation)
alwaysAlways animate, even when unfocused or backgrounded
custom-shader-animation = true

always is useful for screenshots, recordings, or kiosks. For normal day-to-day use, true is the right default.

Tip

For interactive shader development, build and test your shader on shadertoy.com first, then drop it into Wintty. The uniform set is intentionally close enough that most Shadertoy shaders work with no edits.

Configuration

OptionPurpose
custom-shaderPath to a shader file (repeatable for shader chains)
custom-shader-animationWhen to run the animation loop (true, false, always)