GLSL Shader

Run a custom GLSL fragment shader over an image; the shader’s own uniforms become sliders, colour pickers and point controls

GLSL Shader

Node type: utility:glsl
Category: Editing

Description

Run a custom GLSL fragment shader over an image; the shader’s own uniforms become sliders, colour pickers and point controls

Canvas ports

These appear as port handles on the left side of the node.

ID Label Details
image Image IMAGE (required)

These render as form fields in the right-side config panel when the node is selected.

No sidebar config fields.

Outputs

ID Label Type
image Shaded Image IMAGE

What it is for

A fragment shader is the smallest useful unit of image processing there is, and one node that runs an arbitrary one replaces a dozen single-purpose effect nodes. Vignette, grain, chromatic aberration, halftone, duotone, posterise, scanlines, bloom, a bespoke grade. All of them are a few lines of GLSL, and this node runs them on your wired image in the browser for free.

It is also the most agent-friendly node in the product: an LLM can write GLSL, so "give me a warm halftone with an adjustable dot size" is one prompt away from a working control panel.

The contract

You write a fragment shader BODY. The node declares these for you, so do not declare them yourself:

Declared for you What it is
uniform sampler2D tex The wired image
uniform vec2 resolution Output size in pixels
in vec2 uvs Texture coordinates, 0..1
out vec4 outColor What you write your pixel to

The #version line and the precision qualifiers are ours too. If you paste a shader that carries its own #version, it is ignored rather than breaking the compile.

The smallest shader that works:

void main() {
  outColor = texture(tex, uvs);
}

Uniforms become controls

Every float, vec2 and vec3 uniform you declare turns into a control in the editor, and its value is saved with the node.

You declare You get
uniform float amount; A slider, 0..1
uniform float amount; // min -2 max 2 A slider, -2..2
uniform vec2 center; An x / y pair
uniform vec3 tint; A colour picker

Add default to the same comment to set the starting value: // min 0 max 4 default 1.5, or // default #ff8800 for a colour.

Precision qualifiers are fine: uniform highp float amount; reads exactly like the plain form.

If you give a range but no default, the control starts at the MIDDLE of it, so a pasted shader shows you its effect instead of previewing as a no-op.

Anything else is refused with a message rather than quietly ignored: arrays, uniform float a, b; on one line, vec4, int, mat3, extra samplers. A control the node cannot build is a uniform the node would never bind, and a shader running on an unbound uniform is worse than one that will not save.

Two more things it will tell you about rather than swallow: a declaration missing its semicolon, and a block comment you never closed (which otherwise hides every declaration after it).

What you cannot do

#extension directives do not work. They have to precede everything else in the unit, and the node's own declarations come first, so the driver rejects them. Nothing outside core GLSL ES 3.0 is available.

There is one texture, tex, and no way to add a second, so multi-input effects (blends, displacement maps) are out. The output is one image at the source image's size.

Nothing stops a loop that never ends. A for or while whose condition never goes false compiles fine, and then it runs on the real GPU: the tab freezes until the browser's watchdog kills the WebGL context, and the editor comes back with a lost-context error rather than an image. Nothing is charged and nothing is saved, but you will lose the frame you were rendering. Bound your loops with a constant.

Presets

Three shaders ship in the preset menu (vignette, film grain, chromatic aberration) plus a passthrough to start from. They are just source text: load one, then change it. There is nothing special about a preset once it is in your editor.

Errors

Compile errors appear under the source with the line numbers remapped onto YOUR lines, not the assembled ones. Save is disabled while any error is showing, and a shader that fails at full resolution writes nothing at all, so the node keeps serving its last good image instead of a blank one.

What it costs

Nothing. The shader runs on your own GPU and the result goes straight to storage. It is a free node, so it has no Run button.

It does not re-render itself during a workflow run, though. A run echoes the image you last saved from the editor — the shader only ever executes in the editor, on your machine. So if the card is showing Re-render needed, running the workflow will not clear it; open the editor and save. Until you do, the run hands downstream the previous image (or, if you have never saved one, the upstream image untouched).

Re-render needed

The output is stamped with the identity of the shader source, every uniform value, and the upstream image. Change any of them and the card shows Re-render needed. It keeps serving the previous image while that badge is up, deliberately: dropping it would fall back to the unshaded upstream photo, and a paid node downstream would then process the wrong image while looking perfectly healthy. Open the editor and save again to clear it.


Auto-generated from the Wireflow node registry.

© 2026 Wireflow. All rights reserved.

GLSL Shader | Wireflow Docs