diff --git a/docs/custom-shaders.rst b/docs/custom-shaders.rst
index 40c113531..56db6eea4 100644
--- a/docs/custom-shaders.rst
+++ b/docs/custom-shaders.rst
@@ -18,6 +18,7 @@ for example::
:format: html
:class: sd-text-muted small code literal
+.. highlight:: hlsl
Cursor trails
----------------
@@ -37,3 +38,56 @@ Mouse effects
.. include:: generated/custom-shaders-mouse.rst
+
+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. The
+second part is a *pipeline* file, which is responsible for specifying how
+different custom shaders are grouped together, ow 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.
+
+When you set the :opt:`custom_shaders XXX ` setting in :file:`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 takes place by first looking in the :file:`shaders`
+sub-directory of the kitty config directory, if not found, among the shaders
+shipped with kitty. So for shader ``XXX`` first ``XXX.pipeline`` and then
+``XXX.slang`` are searched for.
+
+The shader part
+^^^^^^^^^^^^^^^^^
+
+This is in a :file:`.slang` file. It must define a function called
+``fragment_main()`` whose signature is:
+
+.. literalinclude:: ../kitty/shaders/custom/sample.slang
+ :start-at: public float4 fragment_main(
+ :end-before: END_FUNCTION_SIGNATURE
+
+The two structs passed into this function have the definition shown below:
+
+.. literalinclude:: ../kitty/shaders/custom/types.slang
+ :start-at: public struct KittyCustomShaderData {
+ :end-before: END_TYPES_DEFINITION
+
+Shaders take their inputs and use them to transform the color as they see fit.
+
+The pipeline part
+^^^^^^^^^^^^^^^^^^^^
+
+TODO
+
+Animation events
+^^^^^^^^^^^^^^^^^^^
+
+TODO
diff --git a/kitty/shaders/custom/sample.slang b/kitty/shaders/custom/sample.slang
index 7b13d111d..51a4fb709 100644
--- a/kitty/shaders/custom/sample.slang
+++ b/kitty/shaders/custom/sample.slang
@@ -8,19 +8,24 @@ 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 viewport used for this group. In the form (x, y, width, height)
// where (x, y) is the bottom-left corner of the viewport, with (0, 0) at
// the bottom-left of the screen and y increasing upwards (standard UV
// coordinates). All numbers are unit floats. If no viewport is defined for
// the group defaults to (0, 0, 1, 1) that is, the full backbuffer.
float4 viewport,
+
// The value after applying the animation easing curve to time since
// animation start.
float animation_progress
-) {
+)
+{ // END_FUNCTION_SIGNATURE
return float4(color.r, min(max(0.1, color.g) * 2, 1), color.b, color.a);
}
diff --git a/kitty/shaders/custom/types.slang b/kitty/shaders/custom/types.slang
index f72169fdb..fbd0d4358 100644
--- a/kitty/shaders/custom/types.slang
+++ b/kitty/shaders/custom/types.slang
@@ -76,3 +76,4 @@ public struct KittyTextures {
public float2 pos; // the position of this pixel in the textures (UV coordinates)
}
+// END_TYPES_DEFINITION