06 / LiveCode · Manual

WRITE
SHADERS.

LiveCode is a source module that lets you write Metal shaders inside Patchframe. You write a function that returns a color for every pixel — and the result appears in real time.

1 / Structure

The mainImage function

Every LiveCode shader must define one function called mainImage. The module calls it once per pixel, every frame.

float3 mainImage(float2 uv, constant Uniforms &u)
{
    return float3(0.5, 0.5, 0.5);  // grey
}
  • float3Return value — the pixel color as (R, G, B), each 0.0–1.0.
  • uvPixel coordinate. uv.x 0–1 left to right, uv.y 0–1 bottom to top.
  • uUniforms struct — time, resolution, and eight CV inputs from the patch.
2 / Uniforms

Built-in variables

The u struct gives you everything the running patch knows about the current frame.

VariableTypeDescription
u.resolutionfloat2Canvas size in pixels (width, height).
u.timefloatSeconds since shader start.
u.cv[0] … u.cv[7]floatEight CV inputs (0–1), wired from LFO, Audio Follow, Step Seq, or any CV source.

Time animation

float3 mainImage(float2 uv, constant Uniforms &u)
{
    float v = sin(uv.x * 10.0 + u.time);
    v = v * 0.5 + 0.5;  // remap -1..1 → 0..1
    return float3(v, v, v);
}

CV control

Connect an LFO or other CV module to the LiveCode CV0 port, then reference it as u.cv[0] in the shader. All eight inputs work the same way.

float3 mainImage(float2 uv, constant Uniforms &u)
{
    float freq = 5.0 + u.cv[0] * 20.0;   // CV0 drives frequency
    float v = sin(uv.x * freq + u.time);
    v = v * 0.5 + 0.5;
    return float3(v, v * 0.5, 1.0 - v);
}
3 / Coordinates

UV space

uv is normalized: (0, 0) is the bottom-left corner, (1, 1) is the top-right. For effects that should look the same at any aspect ratio — circles, squares — correct for the canvas proportions:

float2 p = uv * 2.0 - 1.0;                         // center at (0,0), range -1..1
p.x *= u.resolution.x / u.resolution.y;            // aspect correction

Color gradient

float3 mainImage(float2 uv, constant Uniforms &u)
{
    return float3(uv.x, uv.y, 0.5);
}

Circle

float3 mainImage(float2 uv, constant Uniforms &u)
{
    float2 p = uv * 2.0 - 1.0;
    p.x *= u.resolution.x / u.resolution.y;
    float d = length(p);
    float circle = 1.0 - smoothstep(0.3, 0.35, d);
    return float3(circle, circle, circle);
}

Polar coordinates

Convert to angle and radius for radial and spiral effects.

float3 mainImage(float2 uv, constant Uniforms &u)
{
    float2 p = uv * 2.0 - 1.0;
    p.x *= u.resolution.x / u.resolution.y;
    float angle = atan2(p.y, p.x);
    float radius = length(p);
    float v = sin(radius * 8.0 - u.time * 2.0) * 0.5 + 0.5;
    return float3(v, v * 0.5, 1.0 - v);
}
4 / Metal functions

Useful built-ins

Metal Shading Language provides the full set of GPU math functions. These are the ones you will reach for most often in LiveCode:

FunctionWhat it does
sin(x), cos(x)Sine and cosine.
floor(x), fract(x)Integer part, fractional part.
mix(a, b, t)Linear interpolation: a + (b − a) * t.
smoothstep(e0, e1, x)Smooth 0→1 transition between edges.
length(v)Vector length.
dot(a, b)Dot product.
atan2(y, x)Angle in radians.
min(a, b), max(a, b)Minimum, maximum.
clamp(x, lo, hi)Clamp to range.
abs(x)Absolute value.
pow(x, y)Power — useful for gamma and contrast curves.
step(edge, x)Hard cutoff: 0 below edge, 1 at or above.

You can also define #define PI 3.14159265359 and #define TWO_PI 6.28318530718 at the top of your shader. Some built-in snippets already include these.

5 / Recipes

From simple to complex

Sine stripe

float3 mainImage(float2 uv, constant Uniforms &u)
{
    float v = sin((uv.x + u.cv[0]) * 10.0 + u.time);
    v = v * 0.5 + 0.5;
    return float3(v, v * v, 1.0 - v);
}

Plasma

float3 mainImage(float2 uv, constant Uniforms &u)
{
    float2 p = uv * 10.0 - 5.0;
    float v = sin(p.x + u.time + u.cv[0] * 3.0);
    v += sin(p.y + u.time * 0.7 + u.cv[1] * 2.0);
    v += sin(length(p) + u.time * 0.5);
    v = v * 0.33 + 0.5;
    return float3(v, v * 0.8 + 0.2, 1.0 - v * 0.5);
}

Pseudo-noise

float hash(float2 p) {
    return fract(sin(dot(p, float2(127.1, 311.7))) * 43758.5453);
}

float3 mainImage(float2 uv, constant Uniforms &u)
{
    float2 p = uv * (10.0 + u.cv[0] * 10.0);
    float n = hash(floor(p));
    return float3(n, n, n);
}

Helper functions

You can define helper functions above mainImage. If a helper needs u.time or u.cv, pass the whole struct:

float circle(float2 p, float r) {
    return 1.0 - smoothstep(r - 0.02, r + 0.02, length(p));
}

float3 mainImage(float2 uv, constant Uniforms &u)
{
    float2 p = uv * 2.0 - 1.0;
    p.x *= u.resolution.x / u.resolution.y;
    float c = circle(p, 0.3 + u.cv[0] * 0.4);
    return float3(c, c * 0.5, 1.0 - c);
}
float myEffect(float2 p, constant Uniforms &u) {
    return sin(length(p) * 5.0 + u.time + u.cv[0]);
}

float3 mainImage(float2 uv, constant Uniforms &u)
{
    float2 p = uv * 2.0 - 1.0;
    float v = myEffect(p, u) * 0.5 + 0.5;
    return float3(v, v, v);
}
6 / Workflow

Using the editor

  • 1Add LiveCode from Sources.
  • 2Click the module and open the LiveCode editor window.
  • 3Browse the snippet library in the left panel — Attractor, Plasma, Lava, Voronoi, and more. Load one to start from working code.
  • 4Edit, then press Compile — or turn on Auto to compile after each pause.
  • 5Wire LFO, Audio Follow, or any CV source into CV0–CV7 for live control.
  • 6Connect Out to an effect or mixer chain, then to Output.

A failed compile keeps the previous successful output on screen, marks the editor red, and shows the compiler error. If no compile has succeeded yet, output is black.

LiveCode always has exactly eight CV ports. Editing the shader code does not change the port list — it is not dynamic like ISF. Use whichever CV inputs you need inside mainImage and leave the rest unconnected.

7 / Troubleshooting

Common errors

ErrorCauseFix
use of undeclared identifier 'u' Helper function uses u without receiving it. Add constant Uniforms &u as a parameter.
no matching constructor for float3 Wrong number of arguments. float3 needs exactly 3 components: float3(r, g, b).
unknown type name 'in' GLSL syntax pasted into Metal. Remove in / out qualifiers from function parameters.
Distorted aspect ratio Using raw uv for circles or squares. Multiply p.x by u.resolution.x / u.resolution.y.
Sluggish frame rate Heavy per-pixel math or large loops. Reduce iteration count, simplify expressions, or lower canvas resolution.
8 / Further reading

Learn more

  • →Snippet library — browse the built-in collection inside the LiveCode editor. Each snippet is a working shader you can modify.
  • →The Book of Shaders — free online guide to fragment shaders. Written in GLSL, but the concepts translate directly to Metal.
  • →Shadertoy — community gallery of GLSL shaders. Port ideas to Metal by replacing fragCoord / iResolution with uv and iTime with u.time.
  • →LiveCode module reference — ports, controls, and starting patch.
Next

Back to docs.