Custom Shaders¶
Added in version 0.49.0.
Custom shaders in kitty are event driven and allow for all manner of visual
effects from the fun and blingy to useful visual aides. Users can write their
own custom shaders or use some from the large set that ship with kitty.
Browse the categories below to watch some custom shaders that ship with kitty in
action. To use a custom shader add custom_shaders to kitty.conf,
for example:
custom_shaders inside-the-matrix
You can see the code for the custom shaders that ship with kitty here.
Cursor trails¶
You must have enabled cursor trails with something like cursor_trail 1 in kitty.conf for
these shaders to take effect.
When the cursor moves quickly, the trail can appear to hop from place to place
instead of gliding. The cursor-trail-motion-blur shader smooths this out
the way a camera does, by blurring the trail slightly along the direction it
is moving, and it also smooths the trail’s jagged edges. Enable it with
custom_shaders cursor-trail-motion-blur. The options it supports are
explained at the top of the shader file.
The cursor-trail-railgun, cursor-trail-torpedo and
cursor-trail-pixiedust shaders make particles fly off the cursor as it
moves, in the style of neovide. You can change the
size, speed, color, lifetime, etc. of the particles, as explained at the top of
the shader file.
Make the cursor trail glide smoothly, like a fast moving object caught on camera.
cursor-trail-motion-blur
Set your cursor on fire as it moves around.
cursor-trail-blaze
Make your cursor shoot lightning as it moves around.
cursor-trail-lightning
Fire a spiral of particles as your cursor moves around.
cursor-trail-railgun
Leave a wake of particles behind your cursor as it moves.
cursor-trail-torpedo
Sprinkle glittering pixie dust as your cursor moves around.
cursor-trail-pixiedust
Animated backgrounds¶
See the bones of reality.
inside-the-matrix
The ethereal Aurora Borealis.
northern-lights
Celebrate the sheer awesomeness of your terminal.
fireworks
Pretend you are cool enough to code underwater.
water
Mouse effects¶
Clicking is like throwing stones in a pond.
pond-ripple
Spotlight your mouse pointer as it moves around.
spotlight
Retro Terminals¶
Your terminal deserves to have curves.
crt
Do you have the blues?
crt-blue
You are too modern for CRT
tft
Customising and composing shaders¶
While you can always customise the shader by editing the shader itself, this is
overkill. Often shaders declare parameters that you can tune to customise their
appearance. If you open the shader file such parameters are often declared near
the top as static const variables. You can customise these using pipeline
files without needing to edit the shader itself. You can also compose multiple
shaders to create sophisticated effects via pipeline files. Pipeline files are
explored in full detail below, here we will see a quick example to get you
started:
startgroup
var float4 TINT = float4(0, 0.8, 0.6, 1)
shaders crt
endgroup
startgroup
animation_start os-window-focus-in | user-activity
animation_stop os-window-focus-out | user-idle
shaders spotlight
endgroup
This pipeline combines two shaders, the crt shader and the spotlight on
mouse shader. In the first group we have the crt shader and its color has been
customised. The second group defines the spotlight shader and specifies exactly
when the spotlight animation should start and stop.
Controlling shaders with key presses¶
Groups can respond to events you send from a mapping in kitty.conf
using the shader_event action. Such events are named in the pipeline
with a user: prefix. For example, to show the spotlight for a couple of
seconds when you press F1, so that you can find the mouse pointer,
create the pipeline file shaders/find-pointer.pipeline in the kitty config
directory with:
startgroup
animation_start user:find-pointer
animation_stop 2000
shaders spotlight
endgroup
and in kitty.conf:
custom_shaders find-pointer
map f1 shader_event find-pointer
Use animation_toggle to turn an effect on with one press and off with the
next:
startgroup
animation_toggle user:crt
shaders crt
endgroup
Here map f2 shader_event crt toggles the crt effect. Events are sent to
the active OS window, use map f2 shader_event crt all to send them to all OS
windows. You can also send them from scripts with remote control, for example:
kitten @ action shader_event crt. Groups that are not active are not drawn
at all, so an effect that is turned off costs nothing.
As another example, to blend inactive windows toward gray instead of black, save the
following as shaders/dim-gray.pipeline in your kitty config directory and
set custom_shaders dim-gray and inactive_text_alpha 1 in kitty.conf:
startgroup
animation_step 0
var float HIGHLIGHT_INTENSITY = 0
var float BORDER_WIDTH = 0
var float INACTIVE_DIM = 0.74
var float3 INACTIVE_DIM_COLOR = float3(0.2158605)
var bool DIM_CENTRAL_AREA_ONLY = true
var bool INCLUDE_WINDOW_PADDING = true
shaders focus-highlight
endgroup
This uses the same shader as dim-inactive-windows. INACTIVE_DIM is the
fraction of the original color retained: 0.74 blends in 26% of the target
color. INACTIVE_DIM_COLOR is in linear RGB; 0.2158605 corresponds to
sRGB #808080. The default target is black, preserving the existing dimming
effect. The two optional flags preserve the tab bar and include the active
window’s title bar, margin, border and padding in its unchanged area. Explicit cell backgrounds
and images are blended together with text, while transparency and colors reported to
terminal applications are preserved. animation_step 0 makes this static
effect redraw only when content or shader events change.
Anatomy of a custom shader¶
Shaders in kitty are written in slang which is a shading language that compiles down to the actual shading language used by the underlying platform. A custom shader consists of two parts: the actual shader, which is basically a single function that takes an input color and some input uniforms and textures and outputs the resulting color. Secondly, a pipeline file, which is responsible for specifying how different custom shaders are grouped together, how they render, what animation trigger events they respond to, etc. The two parts are described below.
Custom shaders are run at the very end of the kitty rendering pipeline, when everything else has already been rendered. Note that all colors are in the linear RGB color space and co-ordinates are in the traditional UV co-ordinate system with its origin in the lower left corner and Y increasing upwards.
How shaders are loaded¶
When you set the custom_shaders XXX setting in kitty.conf kitty
tries to load a pipeline file with that name and if no pipeline file is found
but a shader with that name is found instead, it is loaded with a default
pipeline file. Loading of pipeline files takes place in the following order:
If the specified pipeline file is an absolute path, it is loaded directly. A leading
~and environment variables are expanded.If a relative path it is loaded from the
shaderssub-directory inside the kitty config directoryIt is looked for amongst the custom shaders shipped with kitty
A default pipeline file is constructed
The .pipeline extension is added automatically if not present. If the
name ends with .slang, no pipeline file is looked for and the shader is
loaded directly, which is useful when a pipeline and a shader have the same name.
The shaders that a pipeline references are first looked for in the directory
from which the pipeline file is loaded, then they follow the same order as for
pipeline files. For shaders, the name is first tried exactly as specified and
then with the .slang extension added.
The shader part¶
This is in a .slang file. It must define a function called
fragment_main() whose signature is:
public float4
fragment_main(
// The color from the previous custom shader in this group or from the
// backbuffer if this is the first shader in the group
float4 color,
// See types.slang for details on the data in this structure
KittyTextures t,
// See types.slang for details on the data in this structure
KittyCustomShaderData d) {
The two structs passed into this function have the definition shown below:
public struct KittyCustomShaderData {
public float4 src_rect, dest_rect; // used by the vertex shader internally
// global background/foreground colors from kitty options (linear RGB, alpha=1)
public float4 background, foreground;
// background color of the active window in the active tab (linear RGB, alpha=1)
public float4 active_window_background;
// Mouse position in UV coordinates (origin at lower-left).
// Values outside [0, 1] indicate the mouse is outside the OS window.
// The first two co-ordinates are current position, the last two the
// position of the last left mouse press.
public float4 mouse_pos;
// Press state of the first four mouse buttons (left, right, middle, button4).
// Each component is 1.0 if the button is currently held, 0.0 otherwise.
public float4 mouse_button_pressed;
// Geometry of the currently active window in UV co-ordinates (origin bottom-left).
// .xy = lower-left corner of the window, .zw = width and height.
// All components are zero when no active window was rendered this frame.
public float4 active_window_geometry;
// Extents beyond the active content, including a visible title bar, margin,
// border, padding and cell-size compensation.
// .xy = left/bottom, .zw = right/top, in viewport UV units.
public float4 active_window_padding;
// Geometry of the most recently belled window in UV co-ordinates (origin bottom-left).
// .xy = lower-left corner of the window, .zw = width and height.
// If the belled window is not currently visible in the active tab/layout, equals central_area.
// All components are zero until the first bell-in-window event occurs.
public float4 bell_window_geometry;
// Geometry of the central content area of the OS window (the tab area, excluding any tab bar)
// in UV co-ordinates (origin bottom-left).
// .xy = lower-left corner, .zw = width and height.
// Equals the full viewport when no tab bar is visible.
public float4 central_area;
// Cursor trail state (UV coordinates, origin bottom-left, (1,1) top-right).
// All fields are zero when the cursor_trail kitty option is disabled or the trail is inactive.
// The trail is a morphing quadrilateral whose four corners animate toward the cursor position.
// Corner order: 0=top-right, 1=bottom-right, 2=bottom-left, 3=top-left.
// Use animation_start cursor-trail-move / animation_stop cursor-trail-stop to activate.
// animation_progress is NOT tied to trail duration; use cursor_trail_state.x for opacity instead.
public float4 cursor_trail_corners_x; // UV x-coordinates of the 4 animated trail quad corners
public float4 cursor_trail_corners_y; // UV y-coordinates of the 4 animated trail quad corners
// Previous-frame animated trail quad corners. These are available for
// custom shaders that perform temporal effects.
public float4 cursor_trail_prev_corners_x;
public float4 cursor_trail_prev_corners_y;
// .x=left, .y=right, .z=top, .w=bottom UV edges of the current cursor rectangle
public float4 cursor_trail_edge;
// .x=left, .y=right, .z=top, .w=bottom UV edges of the cursor rectangle before the most recent move.
// All zeros until the cursor has moved at least twice (first move establishes current; second move sets this).
public float4 cursor_trail_prev_edge;
// Effective cursor color (linear RGB) and opacity for the active window.
// .rgb = cursor background color, .a = cursor opacity (0..1).
// Both are zero when no active window was rendered this frame.
public float4 cursor_color;
// Effective cursor trail color (linear RGB) and opacity.
// .rgb = trail color (falls back to cursor_color.rgb when cursor_trail_color option is "none").
// .a = trail opacity (0..1); zero when the trail is inactive.
public float4 cursor_trail_color;
// The most recent cursor moves that started a cursor trail, most recent
// first. Unlike the other cursor_trail_* fields these remain valid after
// the trail has finished, so effects started by a move can outlive the
// trail and effects from several moves can overlap.
// .x=left, .y=right, .z=top, .w=bottom UV edges of the cursor rectangle
// before (from) and after (to) the move.
public float4 cursor_trail_history_from[8];
public float4 cursor_trail_history_to[8];
// Seconds since each move, move i is in cursor_trail_history_age[i / 4][i % 4].
// Negative for unused entries.
public float4 cursor_trail_history_age[2];
// the size in pixels of the full underlying viewport we are rendering too,
// before applying any viewport transforms from the current group.
// You can use t.viewport to derive the actual size and position of the
// viewport currently being rendered too.
public uint2 viewport_size_pixels;
public float mouse_pointer_hidden; // 1.0 if the mouse pointer is currently hidden, 0.0 if visible
public float cursor_trail_state; // 1.0 if the cursor trail is actively animating, 0.0 otherwise
// Time in seconds since kitty was started. Note that this loses precision
// the longer kitty runs: it is accurate to 1ms only for the first ~4.7 hours
// and to ~64ms after a week. So for animations use wrapped_time() below,
// and for the time elapsed since an event, use the various *_age fields.
public float timestamp;
public float last_rendered_at; // time of previous render, same epoch and precision as timestamp
public uint frame_counter; // cumulative frame counter increments by one every time a frame is fully rendered, first frame is zero
// Time (same epoch and precision as `timestamp`) of the most recent cursor position change that triggered a trail.
// Zero until the cursor has moved at least twice. Pair with cursor_trail_prev_edge.
// Use cursor_trail_age instead to find how long ago this was.
public float cursor_trail_change_time;
// timestamp split into whole seconds and the fraction of the current
// second, which together are exact however long kitty runs. Usually you
// want to use wrapped_time() below instead of these.
public uint timestamp_seconds;
public float timestamp_fraction; // in [0, 1)
// Seconds between the previous render and this one, zero for the first render.
public float time_since_last_render;
// Seconds since cursor_trail_change_time, negative when cursor_trail_change_time is zero.
public float cursor_trail_age;
// Seconds since kitty was started, wrapped to [0, period_seconds). Unlike
// timestamp, this keeps sub-millisecond precision however long kitty runs,
// as long as period_seconds is at most an hour or so. The value jumps back
// to zero once every period, so either use a period over which your
// animation repeats seamlessly, or a long one so that the jump is rare.
public float
wrapped_time(uint period_seconds) {
return float(timestamp_seconds % period_seconds) + timestamp_fraction;
}
}
// A texture kitty renders into, addressed in the same UV co-ordinate space as
// KittyTextures.pos. kitty renders into textures that are at least as large as
// the largest OS Window viewport, so the pixels for the current OS Window
// occupy only the lower-left corner of the texture after the window is made
// smaller. Sampling via the Sample() method below hides that detail, so
// shaders never need to know the size of the underlying texture.
public struct KittyTexture {
// The underlying texture. Use this only if you need raw texture UV,
// remember to multiply your co-ordinates by scale below when you do.
public Sampler2D tex;
// The fraction of tex occupied by the OS Window viewport. Always in (0, 1].
public float2 scale;
// The largest usable co-ordinate for Sample() below. Half a texel less than
// one, so that sampling the top/right edge does not blend in texels from
// outside the viewport.
public float2 max_pos;
// Sample this texture at pos, which is in the same UV co-ordinate space as
// KittyTextures.pos, that is, [0, 1] with the origin at the bottom-left.
// Co-ordinates outside that range are clamped to the edge of the viewport.
public float4
Sample(float2 pos) {
return tex.Sample(clamp(pos, float2(0.f), max_pos) * scale);
}
}
public struct KittyTextures {
// the buffer containing the original rendered pixels from kitty's own rendering. This will
// be updated with the output color only after all custom shaders in this group have run
public KittyTexture backbuffer;
// The following are named textures that can be sampled from in custom
// shaders. The persist texture will persist across frames, anything
// written to it in render number N can be read from it in subsequent
// renders.
public KittyTexture a;
public KittyTexture b;
public KittyTexture persist;
public float2 pos; // the position of this pixel in the viewport (UV coordinates, [0,1] range, origin at bottom-left)
// Some group related uniforms. These are here rather than in
// KittyCustomShaderData as that is shared by all groups, while these can
// differ from group to group.
// The viewport for this group in the form (x, y, width, height) where (x, y) is the
// bottom-left corner, with (0, 0) at the bottom-left of the screen and y increasing upwards
// (UV coordinates). Defaults to (0, 0, 1, 1) when no viewport is defined for the group.
public float4 viewport;
// Goes from zero to one over animation_duration after the group's
// animation starts, with the animation_curve applied, then stays at one.
// If animation_reverse is set, it goes back down to zero after the
// animation stops, going up and down again animation_loops - 1 more
// times. Always zero for groups that run on every frame and for
// groups that have neither animation_duration nor a stop duration.
public float animation_progress;
// The index of the current group in the pipeline.
public int group;
}
Shaders take their inputs and use them to transform the color as they see fit.
Shaders that move content¶
A shader that draws content somewhere other than where kitty put it, such as
the crt shader curving the screen, makes the mouse pointer and the text
under it disagree, so that clicks and selections land on the wrong cells. To
fix that, the shader can also define a function that tells kitty where the
content shown at a given position actually is:
public float2
pointer_map(float2 pos, KittyCustomShaderData d) {
return warp(pos); // the same function fragment_main() uses to sample the backbuffer
}
pos and the return value are in the same UV co-ordinates as t.pos.
The function must be public and return float2. kitty evaluates it on a
grid only when the pipeline is loaded and when the OS Window is resized, and
uses it to move all pointer events, so the only field of d it may use is
d.viewport_size_pixels. Only shaders in groups that draw to the whole
screen, that is, without attach, output_texture, viewport_pos or
viewport_size, and that are either always active or active until an event
turns them off, that is, without an animation_stop duration, are used,
since only they move content for any length of time. For a group that is
turned on and off by events, such as one using animation_toggle, the
function is used only while the group is active, so a shader that moves
content can be turned on and off with a key press. When several shaders define it, they are applied
starting from the last one to run.
Note that d.mouse_pos then contains the mapped position, that is, the
position of the content under the mouse before it was moved. Effects that draw
at the mouse position line up with the pointer when they run before the shader
that moves content, not after it.
The pipeline part¶
A pipeline file (.pipeline) is a plain text file that controls how
one or more shaders are assembled into a rendering pipeline. Lines starting
with # are comments, as is everything after a # that is preceded by
whitespace; blank lines are ignored.
Top-level directives (outside any group):
slot endThe rendering slot. Currently only
endis supported (the shaders run after all of kitty’s own rendering is complete). This is the default and can be omitted.textures a b persistDeclares which named textures the pipeline uses. List only the names you need — each one causes an off-screen framebuffer to be allocated. The available names are
a,b, andpersist; see Named textures below for their semantics.var <type> <name> <value>Sets a pipeline-level shader variable. Any
static constdeclaration in a shader whose name matches<name>is replaced withstatic const <type> <name> = <value>;before compilation, baking the value in. This is the mechanism for tuning shader parameters without touching the shader source. Supported types areint,uint,float,double,booland their vector variants (float2,float3,float4,int2, etc.). Pipeline-level variables apply to every group; group-levelvardirectives (see below) take precedence within that group.
Groups¶
A group is the unit of rendering. Each group runs a chain of shaders in
sequence, with the output color of one shader feeding as the input color
to the next. A pipeline may contain up to 16 groups.
startgroup
shaders <name1> [name2 …]
# optional per-group settings
endgroup
Directives inside a group:
shaders <name> [name …]One or more shader names to run in order. Shaders are searched for first in the directory containing the pipeline file, then in the
shaders/subdirectory of the kitty config directory, then among the shaders shipped with kitty. Absolute paths, including ones starting with~, are loaded directly.var <type> <name> <value>Same as the top-level
varbut scoped to this group. Merged with pipeline-level vars; the group value wins on conflict.viewport_pos <x> <y>The bottom-left corner of this group’s rendering region, expressed as unit floats in UV coordinates (0,0 = bottom-left of the screen, 1,1 = top-right). Defaults to
0 0. The final group must use this default, since it always covers the full screen. Non-default values are rejected.viewport_size <w> <h>The width and height of the rendering region as unit floats. Defaults to
1 1. The final group must use this default; non-default values are rejected.output_texture <name>Where the group writes its output. The default (
default) ping-pongs the backbuffer: the rendered result becomes the new backbuffer that subsequent groups read fromt.backbuffer. Setting this toa,b, orpersistinstead writes into the corresponding named texture; the backbuffer is left unchanged for the next group. The final group must always use the default output.animation_start <event>[|<event> …]Events that trigger the start of this group’s animation. Multiple events are separated by
|. A group with neither this noranimation_togglenorattachruns on every frame unconditionally. See Animation events below for the full list.animation_stop <token>[|<token> …]When to stop the animation. Tokens are separated by
|and may be:An event name — the animation stops when that event fires.
An integer — a duration in milliseconds after which the animation automatically stops. Unless
animation_durationis set, theanimation_progressvalue will smoothly reach1.0at that point.never— the animation runs indefinitely until an explicit stop event.
When
animation_stopis omitted kitty usescursor_stop_blinking_afteras the duration.animation_curve <curve>A CSS easing function that maps raw elapsed time to the
animation_progressvalue delivered to the shader. Supported values:Named curves:
linear,ease,ease-in,ease-out,ease-in-out,step-start,step-endcubic-bezier(x1, y1, x2, y2)linear(p0, p1[, …])steps(n, start|end)
Defaults to a linear mapping (no easing).
animation_duration <ms>How many milliseconds the
animation_progressvalue takes to go from0.0to1.0after the animation starts. It then stays at1.0until the animation stops. This is useful for effects that should fade in and then stay on, for example ones turned on byanimation_toggle. Defaults to theanimation_stopduration. Note that groups with no stop duration, such as those usinganimation_stop neveror onlyanimation_toggle, always have ananimation_progressof0.0unless this is set.animation_reverse yes|no|<ms>Whether to play the animation in reverse when it stops, for any reason, instead of turning the group off immediately. The group then stays active while
animation_progressgoes back down to0.0, using the sameanimation_curve, and turns off once it gets there. Withyesthis takes as long asanimation_duration, a number sets the time in milliseconds instead. If the animation is stopped beforeanimation_progressreaches1.0it goes back down from wherever it was, and if it is started again while going back down, it goes up again from wherever it was. Stop events are ignored while playing in reverse. Defaults tono. For example, to fade thecrteffect in and out over half a second when toggling it:startgroup animation_toggle user:crt animation_duration 500 animation_reverse yes shaders crt endgroup
Note that the
crtshader does not actually useanimation_progress, you would need to modify it to do so.animation_loops <n>How many times to play the animation forwards and in reverse when it stops. Can only be used together with
animation_reverse. After the first reverse finishes,animation_progressgoes from0.0to1.0overanimation_durationand immediately back down again, without staying at1.0, until it has gone up and downntimes in all, after which the group turns off. Stop events are ignored while looping, start and toggle events turn the group back on, continuing from the current progress. Defaults to1. For example, to blink three times when a key is pressed, with an animation that stops as soon as it has risen to1.0:startgroup animation_start user:blink animation_duration 150 animation_stop 150 animation_reverse yes animation_loops 3 shaders my-blink-shader endgroup
animation_step <ms>How many milliseconds between animation frames. Lower values produce smoother animation at the cost of more GPU draws. Defaults to
50ms (20 fps). The value is clamped to be no smaller thanrepaint_delay. Set this to0for static effects that should redraw only when content or shader events change, without periodic frames. Animation stop events and duration limits still apply.animation_toggle <event>[|<event> …]Events that start this group’s animation when it is not running and stop it when it is. This is mostly useful with
user:events sent by theshader_eventaction to turn effects on and off from a mapping. A toggle takes precedence over start and stop events in the same frame. A group that hasanimation_togglebut neitheranimation_startnoranimation_stopkeeps running until it is toggled off, rather than stopping aftercursor_stop_blinking_after.attachMark this group as attached to the preceding group. An attached group is automatically active whenever its preceding group is active, without needing to duplicate the
animation_start/animation_stopdirectives. This is the primary way to build multi-pass effects where several groups must activate and deactivate together. The first group in a pipeline cannot useattach. An attached group may also carry its ownanimation_startoranimation_toggle— in that case it becomes active when either condition is true (its own events or the preceding group being active). If an attached group has neitheranimation_startnoranimation_toggleof its own, it mirrors the preceding group exactly: it activates when that group activates and deactivates when that group deactivates, and has the sameanimation_progressas that group, so both groups animate in perfect sync. Its ownanimation_curve,animation_durationandanimation_reverseare ignored.
Named textures¶
Named textures are additional off-screen buffers accessible to all shaders in
the pipeline via the KittyTextures struct (t.a, t.b, t.persist).
a,bScratch textures that exist for the lifetime of the pipeline. They start uninitialized at the start of each draw call. Their typical use is for intermediate rendering: a group renders into
aviaoutput_texture a, and a later group readst.ato combine it with the backbuffer.persistLike
a/bbut survives across frames. Whatever is written tot.persistduring frame N can be read back fromt.persistduring frame N+1. This allows effects that accumulate state over time (e.g. simulation steps, trails, fluid simulations).
All three named textures cover the same area as the OS Window viewport and are
sampled in the same UV co-ordinate space as t.pos, via the Sample()
method on KittyTexture. Note that the underlying GPU textures can be larger
than the viewport, since kitty grows them to fit the largest OS Window and
never shrinks them again, so always sample via Sample() rather than using
the raw tex sampler. They must be declared in the top-level textures
directive before they can be referenced. A named texture that is the output
target for the current group cannot simultaneously be sampled as input; kitty
automatically substitutes the backbuffer in that case.
How groups chain together
The backbuffer starts out as kitty’s fully rendered terminal frame. Each group
reads from t.backbuffer and writes somewhere:
output_texture default(the default): the group’s output becomes the new backbuffer. The next group reads the modified pixels. This is the standard way to chain post-processing passes.output_texture a|b|persist: the group writes into the named texture instead, leaving the backbuffer intact for the next group.
Groups with animation_start, animation_toggle or attach are skipped
entirely when their animation is not active, saving GPU work. Groups without
any of these directives run on every frame.
A minimal pipeline — one shader, event-driven animation:
startgroup
animation_start pointer-left-button-press
animation_stop 1500
animation_curve ease-out
animation_step 16
shaders pond-ripple
endgroup
A two-group pipeline using named textures:
textures a
startgroup
shaders bloom-prepass
output_texture a
endgroup
startgroup
shaders bloom-composite
endgroup
Here the first group renders a glow pre-pass into texture a, and the
second group reads both the original backbuffer (t.backbuffer) and the
glow data (t.a) to composite the final image. Note that these shaders
aren’t shipped with kitty, this is jut an illustrative example.
A multi-pass event-driven effect using attach:
textures a
startgroup
animation_start pointer-left-button-press
animation_stop 1500
animation_curve ease-out
animation_step 16
shaders ripple-prepass
output_texture a
endgroup
startgroup
attach
animation_step 16
shaders ripple-composite
endgroup
The second group uses attach so it activates and deactivates in lockstep
with the first group — no need to repeat the animation_start /
animation_stop / animation_curve directives. Both groups also share
the same animation_progress value so they animate in perfect sync.
Animation events¶
Animation events drive when groups start and stop animating. They are used in
the animation_start, animation_stop and animation_toggle directives. Multiple events can
be combined with | — any one of them will trigger the action.
Event name |
When it fires |
|---|---|
|
The left mouse button is pressed inside the OS window. The click
position is available in |
|
The OS window gains keyboard focus. Also fires on the first frame immediately after the pipeline is loaded. |
|
The OS window loses keyboard focus. |
|
The active kitty window (pane) changes and a new window gains focus.
The focused window’s geometry is in |
|
A kitty window (pane) loses focus. |
|
The active tab changes. |
|
A bell (BEL character) is received in any kitty window.
The geometry of the window in which the most recent bell occurred is
available in |
|
Any keyboard or mouse input is received. |
|
The user has been idle (no keyboard or mouse input) long enough to trigger the idle threshold. |
|
The cursor trail begins moving (requires |
|
The cursor trail stops moving. Typically used as an |
|
Sent by the |
Note that if both a start event and a focus-out event fire in the same frame (for example, a mouse click that simultaneously moves focus away), the focus-out takes priority and the animation is not (re-)started.