Shaders

In the Basic Workflow chapter, you saw that a Shader can generate visuals from scratch, and that Shader Kit modules can be placed before a Shader to transform or modulate an existing preset.

This chapter goes deeper.

Here you will learn what happens inside a Shader, how Shader Kit patches are built, and how to read the flow of coordinates, values, and colors.

What a shader does

A shader calculates an image pixel by pixel.

For every pixel, it asks:

At this position, what color should this pixel be?

The answer can depend on position, time, textures, audio, MIDI, modulation signals, and module parameters.

Because this calculation runs on the GPU, many pixels can be processed at the same time. This makes shaders well suited for real-time visual synthesis, animated patterns, masks, distortions, feedback, and procedural graphics.

Shader, Processor Shader, and 3D Shader

Drambo Visual has three main shader-based modules.

Shader

Generates an image from scratch. It is useful for procedural visuals such as shapes, gradients, patterns, noise, animated textures, and full-screen generative graphics.

Processor Shader

Processes an incoming Texture.

Use it when you already have an image, video, camera feed, Shader, or another Texture, and you want to transform it, distort it, recolor it, blur it, feed it back, or apply another pixel-level effect.

3D Shader

A 3D Shader generates raymarched 3D visuals.

It works with virtual 3D space instead of only flat XY coordinates. This makes it possible to create procedural 3D forms, glowing shapes, repeated spaces, tunnels, wireframes, and abstract geometry.

This chapter focuses mainly on the 2D Shader workflow. The same ideas also appear in 3D Shaders, but 3D uses XYZ space and raymarching.

Rack mode and Code mode

A Shader can work in two modes:

  1. Rack mode

  2. Code mode

This chapter focuses on Rack mode.

In Rack mode, you build a shader visually using Shader Kit modules.

Shader Kit modules look like normal Drambo modules, but they are not separate rendered pictures. Inside a Shader, they become stages of one final GPU shader.

A useful way to think about it:

Shader Kit modules are ingredients of one picture.

 

Code mode is for writing shaders directly in code and is covered separately.

Inside a Shader vs before a Shader

Shader Kit modules can be used in two places.

Inside the Shader

You can open a Shader and place Shader Kit modules inside its rack.

Use this when you want to build the Shader yourself (and save it as a reusable preset).

Before the Shader

You can also place Shader Kit modules directly before a Shader in the main Visual Rack.

Use this when you want to extend or modify a Shader preset without opening it.

Both workflows become part of the Shader’s processing chain.

The difference is mostly practical:

  1. Use modules before a Shader for quick preset modification.

  2. Use modules inside a Shader when building a custom patch or when the structure becomes more complex.

Important:

A Shader Kit module placed before a Shader affects only the immediately following Shader or Processor Shader.

It does not become a general Texture processor for everything after it.

Core Shader Kit flow

A Shader Kit patch is easiest to understand from one complete path.

Here is a minimal visible patch:

Think of the Shader as asking the same question for every pixel:

“What should be drawn here?” 

For each pixel, the Shader provides its current XY position. Mask / Circle uses that position to decide whether the pixel is inside the circle, outside it, or near its soft edge. It outputs the result as V, a single value for that pixel.

You can think of V as an amount: 0 means none, 1 means full, and values between 0 and 1 mean partial amount.

In this patch, V is connected to Alpha on Color / HSVA. The color is visible where V is high and transparent where V is low. Color / HSVA outputs C, the final color for this pixel, and the Shader writes C into its Texture output.

Shader Kit uses these main socket types:

SocketMeaning
XY2D position for the current pixel 
VSingle value calculated for the current pixel 
CColor calculated for the current pixel 
TextureImage output of the Shader

Inside a Shader rack, modules are processed as a chain for each pixel, transforming positions, values, and colors until the Shader produces the final color for the current pixel.

These modules are enough to understand the first Shader Kit patches.

ModuleInputOutputRole in this patch
Shader (container)-XY, TextureProvides the default XY position and outputs the final Texture
XY TransformXYXYTransforms the XY pixel position before it is used by later modules. This changes the coordinate space, creating movement, warping, and distortion.
Mask XYVCreates a value from the current position. This value can represent a grayscale pixel or be used as a modulation source.
ColorV (optional)CCreates a color for the current pixel, often using values or modulation from earlier modules (usually Masks).

Minimal patch, step by step

For every pixel:

  1. The Shader provides the current XY position.

  2. Mask / Circle receives XY and calculates V from the pixel position.  1 - inside the circle, 0 - outside
  3. V modulates Alpha on Color / HSVA, effectively setting alpha to 0 for the pixels outside the circle.
  4. Color / HSVA outputs C.
  5. The Shader writes C to its Texture output.

The important base:

Shader provides XY.
XY Transform changes XY.
Mask generates V from XY.
Color generates C from V.
Shader outputs Texture.

A Mask V output can modulate parameters of other Shader Kit modules.

Reading a Shader Kit Patch

A Shader Kit patch is easiest to read as a calculation that runs for every pixel.

Start with XY: which coordinates are being used or transformed?

Then look for V: which Mask modules are generating shapes, patterns, noises, or other position-based values from those coordinates?

Next, follow how those values are remapped, repeated, mixed, or used to modulate other modules.

Finally, look for C: where the visible color is created and sent to the Shader output.

In short: a patch describes how position becomes value, and how value becomes color.

 

The same Shader as an extension of Shader / Color HSVA. 

 

Masks as values and control signals

A Mask receives an XY position and generates a V value for that position. This value can represent a shape, pattern, gradient, noise, or other grayscale-like information.

A mask can be used as a visible shape, but it can also be used as a modulation source. For example, a Circle Mask can draw a circle, but the same Circle Mask can also control the alpha of a color, the brightness of a texture, or the amount of distortion applied somewhere else.

This is one of the most useful ideas in Shader Kit:

A mask does not have to be the final image.
A mask can control another part of the shader.

In this example, the first mask, Mask / Gradient, modulates the Size parameter of the second mask, Mask / Square.

Because masks are calculated per pixel, they can create detailed local changes inside the image. One area of the screen can receive a strong value, another area can receive a weak value, and another area can receive no value at all.

Think of other use cases:

A gradient can modulate color.
Noise can modulate distortion.
A mask can modulate transparency.
A texture can modulate shader parameters.
RGBA channels can be used as separate modulation sources.

This is where Shader Kit becomes especially flexible. Simple signals can be combined to create much more complex visuals.

Another example:

1. Mask/Gradient Radial modulates Color Hue and another Mask / Noise Caustics modulates Color Alpha.

2. Mask / Circle blur modulates Mask / Hexagon pattern Size and Color module's Hue. Hexagon pattern Mask modulates Color Alpha.

3. One Mask / Hexagon pattern modulates the Size param of the second Mask / Hexagon patterns. They both modulate different Color generator params.

Transforming space

XY Transform modules change the coordinate space before it reaches the following modules.

This means you are not moving a finished image. You are changing the space used to generate the image.

For example, if an XY Transform is placed before a Circle Mask, the transform changes how the circle is drawn. Scaling the coordinates changes the apparent size of the circle. Repeating the coordinates creates many circles. Distorting the coordinates bends or warps the circle.

1. Example: The XY Transform / Tiles preset takes the normal continuous XY coordinate space and splits it into repeated tile areas.

Instead of the Mask receiving one continuous coordinate space for the whole screen, it receives repeated local coordinates for each tile. From the Mask’s point of view, it is drawing the same shape again and again inside many smaller areas.

Depending on the preset settings, these tiled coordinates can be scaled, shifted, warped, or chopped, creating repeated or broken-up versions of the following Mask.

2. XY Transform / Radial Repeat -> Mask / Circle -> Color  . Repeat presets also provide additional outputs, such as Segment Index. This index can be used to modulate parameters of the following modules, making each repeated segment look different.

XY Transforms can be stacked to create rotation, symmetry, repetition, folding, movement, and spatial distortion.

Mask processor 

Work in progress ...  

SDF

Work in progress ...  

Mask repeat

The Mask Repeat module repeats the contents of its internal rack many times. On each iteration, the rack generates a V value. Mask Repeat then combines all iterations into one final V output.

You can think of it as a repeat system for masks: one internal mask patch is evaluated many times, and the results are merged into a single mask value.

Inside the rack, you will find an Index output. You can use it to modulate parameters of the internal modules, so each repeated layer can look different.

In this example, the Index modulates only the square position, but you could also use it to modulate rotation, size, or even a complex chain of XY Transform modules or Time Modulator behaviour.

The Blend parameter controls how the repeated layers are combined. They can be added, subtracted, or smoothly merged. Some blend modes are designed to work with SDFs.

Mask Repeat modules can also be stacked, so one Mask Repeat can be placed inside another.

Color repeat

The Color Repeat rack module repeats the contents of its internal rack many times. On each iteration, the rack generates a C color. Color Repeat then combines all iterations into one final C output.

You can think of it as a repeat system for colors: one internal color patch is evaluated many times, and the results are merged into a single color result.

While Mask Repeat is useful for repeating values, shapes, or SDFs, Color Repeat works with Color signals. This makes it especially useful when you want to blend multiple colored layers.

Each repeated layer can be modified using the rack’s index outputs, so every layer can have a different hue, alpha, position, scale, or other parameter.

4 blend modes are available.  

Use Color Repeat when you want to build layered color structures, repeated gradients, animated color patterns, or differently colored copies of the same visual element.

Time modulator

We can use Drambo DSP modules like LFO to time-modulate the visual parameters, but here we will use a more elegant solution that lives entirely inside the Shader: a Time modulator module.

The Time modulator module is like Mask, that generates the same time driven value for every pixel.

In this example, the Time modulator modulates the Angle of the XY Transform, making the triangle rotate.

When non-modulated, these presets send the same value per-pixel, but we can also modulate time progression using another Mask module.

This lets one Mask change the timing or phase of a Time Modulator module, creating motion that bends, shifts, or varies across the image.

Think of it as time bending.

Feedback and recursion


Shader Kit feedback is built with two modules:

1. Feedback Begin
2. Feedback End

The modules placed between them are evaluated several times, according to the iteration setting.

On the first iteration, the patch starts from the initial feedback values. Feedback End then collects the result. On the next iteration, Feedback Begin outputs the previous result through its XY, V, and C outputs.

This lets the patch feed its own result back into itself. Each iteration can move the coordinates again, change the mask again, add more color, or build a more complex pattern from the previous step.

Feedback can be used for recursive coordinate transforms, folded space, iterative mask modulation, color accumulation, and procedural feedback patterns.

Use Idx to make each iteration different. For example, Idx can change scale, rotation, offset, color, brightness, alpha, or blend amount from one iteration to the next.

In this example Noise Mask is executed 3 times, each time using it's previous V output to modulate it's own Scale param.

Feedback is one of the most powerful areas of Shader Kit. It is best explored gradually: start with a simple mask or transform, use a low iteration count, and modulate one parameter at a time.

Small changes can grow into complex results, making feedback useful for folded shapes, recursive patterns, tunnels, trails, organic motion, and generative structures.

Working with presets

Factory presets are a good starting point for learning Shader Kit.

Instead of building everything from zero, load a preset and inspect how it is made. Look for the basic structure:

Where does the XY signal come from?
Which modules generate masks or values?
Where does the color come from?
Which parameters are modulated?
Which parts are exposed as controls?

You can often create a new visual by changing only one or two parts of an existing preset: replacing a Mask, adding an XY Transform, changing the Color module, or adding modulation.

A useful workflow is:

Start with a simple preset:  Shader/Default
Change one module.
Add one modulation source.
Add one transform.
Then continue only when you understand what changed.

This keeps patches easier to control and makes it easier to learn what each Shader Kit module does.

 

-----------------------------

 

Code your own shaders

Drambo Shader Quick Manual

1. Module Types

Shader presets generate color directly:

float4 render(device Data &data, uint2 tid, float2 uv, float Amount[[param]], float4 Color[[param]]) { return Color * Amount; }

Mask presets usually write one or more float outputs:

void render(device Data &data, uint2 tid, float2 uv [[input]], thread float &Mask [[output,preview]], float Radius [[param]]) { Mask = 1.0 - smoothstep(Radius, Radius + 0.01, length(uv)); }

Color presets write a color output:

void render(device Data &data, uint2 tid, thread float4 &Color [[output,preview]], float4 Tint [[param]]) { Color = Tint; }

Processor Shader presets process input textures:

float4 render(device Data &data, uint2 tid, float2 uv [[input]], texture2d<float> InTexture [[input]], sampler s [[param]], float Amount [[param]]) { float2 texUV = textureUV(data, uv); return InTexture.sample(s, texUV) * Amount; }

2. Coordinates

uv is the main visual coordinate. In current visual presets, treat it as centered/bipolar and already suitable for square visual space. Usually do not apply manual aspect correction with data.width / data.height.

Use:

float2 p = uv;

For texture sampling in processor shaders, convert with:

float2 texUV = textureUV(data, uv);

For pixel/feedback work, use tid:

uint2 size = uint2(tex.get_width(), tex.get_height()); float2 texel = 1.0 / float2(size); float2 pixelUV = (float2(tid) + 0.5) * texel;

3. Parameters

Unipolar knob, normally 0..1:

float Amount [[param]]

Bipolar knob, normally -1..1:

float X [[param,bipolar]]

Color parameter:

float4 Color [[param]]

Sampler parameter for texture sampling:

sampler s [[param]]

For animation, preferred convention:

float Speed [[param,bipolar]], float Time [[param,bipolar]]

Then read only Time in shader code:

float phase = Time * 6.2831853;

Do not also multiply data.time * Speed if using this convention. The host handles the relation between Speed and Time.

4. Useful Built-Ins / Common Metal Functions

Standard Metal math is available:

sin, cos, tan, atan2, pow, exp, log abs, min, max, clamp, mix, step, smoothstep floor, ceil, fract, fmod dot, length, distance, normalize

Drambo helpers seen in presets:

textureUV(data, uv)

This converts Drambo visual uv to normalized texture coordinates for sampling processor inputs.

Some older presets use helpers like rotate(uv, angle), but safest style is to define local helpers:

float2 rot2(float2 p, float a) { float s = sin(a); float c = cos(a); return float2(c * p.x - s * p.y, s * p.x + c * p.y); }

5. Texture Inputs

Processor shader texture input:

texture2d<float> InTexture [[input]]

Sample with normalized coordinates:

constexpr sampler s(filter::linear, address::clamp_to_edge, coord::normalized); float4 col = InTexture.sample(s, textureUV(data, uv));

Read exact pixel:

float4 col = InTexture.read(tid);

Use .sample() for filtered/warped UVs, .read() for exact same-pixel operations.

6. Feedback Textures: Processor Shader Only

Feedback/state textures are available in Processor Shader, especially Time presets:

texture2d<float> stateTex = TEXTURE_BUFFER(RGB32);

Read previous state:

float4 prev = stateTex.read(tid);

Write next state:

stateTex.write(outColor, tid);

Common pattern:

float4 render(device Data &data, uint2 tid, texture2d<float> InTexture [[input]], float Decay [[param]]) { texture2d<float> back = TEXTURE_BUFFER(RGB32); float4 input = InTexture.read(tid); float4 prev = back.read(tid); float4 outColor = max(input, prev * Decay); back.write(outColor, tid); return outColor; }

Use feedback for trails, freeze, blur, reaction-diffusion, drawing buffers, accumulators, temporal differences, previous-frame warps.

Do not use TEXTURE_BUFFER in normal generator Shader presets. It belongs to processor/time-style modules.

7. Practical Rules

Keep Shader presets stateless. They generate pixels from uv, params, and optionally Time.

Use Processor Shader when you need input texture processing or feedback memory.

Prefer uv over manual tid coordinate reconstruction unless doing exact texel feedback.

Avoid aspect correction unless the preset explicitly needs raw screen pixels.

For color params, prefer full names in UI when user-facing: HueSaturationValueAlpha.