Skip to content

Kitty Custom Shaders

GPU post-process effects for kitty ≥ 0.49: GLSL-ish shaders written in Slang, run at the very end of the render pipeline, driven by events (focus, idle, cursor trail, clicks).

Overview

  • Enable with one line in kitty.conf:
    custom_shaders inside-the-matrix
    
    Space-separated names are concatenated in order.
  • Lookup order for a name: absolute path → ~/.config/kitty/shaders/<name> → kitty's shipped set (/usr/lib/kitty/kitty/shaders/custom/) → an auto-generated default pipeline.
  • A bare .slang with no .pipeline still works (default group, animates ~20 fps).
  • Compiles at GL init; artifacts land in ~/.cache/kitty/shaders/. Restart needed — the config-reload path only rebuilds when the custom_shaders option value changes.

Shipped set

category names
backgrounds inside-the-matrix, northern-lights, fireworks, fireworks-rockets, water, underwater
mouse pond-ripple, spotlight
cursor trails (need cursor_trail 1+) cursor-trail-default, -blaze, -lightning, -motion-blur
navigation dim-inactive-windows, focus-highlight, tab-change
retro crt, crt-blue, tft
fragments to compose negative, bloom

Details

Tuning without editing shaders

A pipeline can bake values into any static const in the shader:

# ~/.config/kitty/shaders/dim-gray.pipeline
startgroup
    animation_step 0
    var float INACTIVE_DIM 0.74
    shaders focus-highlight
endgroup

Rules that bite: - The var type and NAME must match the declaration exactly (float vs float3, case sensitive). A mismatch is silently ignored — no warning. - # comments it out. Uncommenting is the only activation step. - animation_start / animation_stop / animation_step control when it redraws, not the effect's internal speed (that's usually a SPEED const multiplied by d.timestamp).

Reload semantics

action rebuilds shaders?
restart kitty yes (reliable)
edit kitty.conf / theme (auto_reload_config) arms the force flag but does not rebuild
kitty @ load-config (kitty_mod+f5) twice yes — first press arms, second rebuilds
edit files in shaders/ only no — the dir is not watched

Legibility lesson

water is a full-screen multiply + UV warp: UV_DISPLACEMENT 0.04 resamples the backbuffer (smears glyphs) and WATER_COLOR 0.5 × 1.2 washes everything grey. underwater and fireworks avoid this by gating on luminance (BLACK_BLEND_THRESHOLD) so only dark pixels are touched.

~/.config/kitty/shaders/water-bg.{slang,pipeline} (kept, currently disabled) keeps the caustics, drops the warp, and adds the luminance gate — text stays crisp.

Gotchas

  • crt explicitly does not work with background_opacity < 1.
  • Cursor-trail shaders do nothing unless cursor_trail > 0.
  • Shaders see linear RGB; UV origin is bottom-left.
  • Validation without restarting: build the pipeline through kitty's own code path (parse_pipeline + build_custom_shader_pipeline_glsl), which runs slangc with -warnings-as-errors all.
  • [[Index]]
  • [[Hal Overlay]]