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-shaderin 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.
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.
The standard Shadertoy uniforms plus Wintty-specific extensions are available:
| Uniform | Type | Description |
|---|---|---|
iChannel0 | sampler2D | The current terminal screen (or the previous shader's output) |
iResolution | vec3 | [width, height, 1] in pixels |
iTime | float | Seconds since the first frame was rendered |
iTimeDelta | float | Seconds since the previous frame |
iFrame | int | Frame counter |
iChannelResolution[0] | vec3 | Same as iResolution (no extra channels are wired up) |
iFrameRate, iChannelTime, iMouse, iDate, and iSampleRate are
declared but not currently populated.
| Uniform | Type | Description |
|---|---|---|
iCurrentCursor | vec4 | Cursor position (xy) and size (zw) |
iPreviousCursor | vec4 | Cursor position and size on the previous frame |
iCurrentCursorColor | vec4 | RGBA cursor color |
iPreviousCursorColor | vec4 | Previous-frame cursor color |
iCurrentCursorStyle | int | Cursor style (block, bar, etc.) |
iPreviousCursorStyle | int | Previous-frame cursor style |
iCursorVisible | int | 1 if the cursor is currently visible, 0 otherwise |
iTimeCursorChange | float | iTime at the last cursor change |
iTimeFocus | float | iTime at the last focus event |
iFocus | int | 1 if focused, 0 otherwise |
iPalette[256] | vec3 | The full 256-color terminal palette |
iBackgroundColor | vec3 | Configured background color |
iForegroundColor | vec3 | Configured foreground color |
iCursorColor | vec3 | Configured cursor color |
iCursorText | vec3 | Configured cursor text color |
iSelectionBackgroundColor | vec3 | Selection background color |
iSelectionForegroundColor | vec3 | Selection 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.
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:
| Value | Behavior |
|---|---|
true (default) | Animate only when the focused terminal uses custom shaders |
false | Only redraw on terminal updates (no animation) |
always | Always 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.
| Option | Purpose |
|---|---|
custom-shader | Path to a shader file (repeatable for shader chains) |
custom-shader-animation | When to run the animation loop (true, false, always) |