Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Rules and limits

The language is small, and so are its rules. Here they all are, in one place, so that when something stops you, you can find out why.

When things go wrong

A shader can go wrong in three places, and I tell you about all of them.

The first is when I read it. A word I don’t know, a bracket that isn’t closed, a <: I stop on the line it’s on, the way I would anywhere else in your program.

SCREEN 320, 240
SHADER "unknown"
    WHEN DRAWING
        SET COLOR = RGBA(TAN(UV.x), 0.0, 0.0, 1.0)
    END WHEN
END SHADER

TAN isn’t one of the shader language’s functions, so I stop at it.

The second is when I build it, as the SHADER line runs. A function given the wrong number of values, a name that was never set, a setting you try to change: I stop and say what it was.

SCREEN 320, 240
SHADER "short"
    WHEN DRAWING
        SET COLOR = RGBA(1.0, 0.0, 0.0)
    END WHEN
END SHADER

RGBA takes four values, and this one has three, so I stop and say so. (RGB is the one that takes three.)

SCREEN 320, 240
SHADER "early"
    WHEN DRAWING
        SET COLOR = RGBA(glow, 0.0, 0.0, 1.0)
        glow = FRACT(TIME)
    END WHEN
END SHADER

glow is used on the line before the one that sets it, so there’s no glow yet where it’s used.

The third is when the graphics chip builds it. What reads as fine to me can still be something the chip won’t run: a color with three parts where it wants four, a sum of a color and a place. Then I stop the game with the chip’s own words for what was wrong, and the shader’s name.

SCREEN 320, 240
SHADER "three"
    WHEN DRAWING
        SET COLOR = VEC3(1.0, 0.0, 0.0)
    END WHEN
END SHADER

SET COLOR wants four parts, and VEC3 has three.

Names

A variable’s name is letters, digits and _, starting with a letter. Big and small letters are the same.

These names are taken, and a variable called any of them stops the shader:

  • Names that start with one of the language’s own words. IMAGE, UV, SCREEN, SCREEN_SIZE, TIME and TICK are read first, so timer, uvs, images and ticks are read as TIME, UV, IMAGE or TICK with something left over. I stop on the line, and say which word the name starts with. Call them clock, place, pictures and count instead.
  • A setting’s name. A variable can’t have the same name as one of the shader’s USE settings: settings can be read, not changed.
  • The names I use to build the shader: uv, in, uniforms and balpha_out.
  • The graphics chip’s own words, such as var, let, fn, if, for, loop, return, struct, type, target, smooth, filter, true and false. The whole list is long, and mostly words nobody would use for a variable by accident. I know them all, and stop on any of them with the name you used.
SCREEN 320, 240
SHADER "clock"
    WHEN DRAWING
        timer = FRACT(TIME)
        SET COLOR = RGBA(timer, 0.0, 0.0, 1.0)
    END WHEN
END SHADER

What a line can be

  • name = expression, or SET COLOR = expression, and nothing else.
  • No IF, loops, FUNCTION, PRINT or DIM.
  • No <, >, = in a sum, AND, OR, NOT or MOD: see Choices without IF.
  • A number is digits with an optional point: 3, 0.25. No 1e-3.
  • A swizzle goes on a name, a word like UV, or brackets, not straight on a function: c = OWNTEXTURE(UV) then c.r.
  • A swizzle has one to four parts, all from rgba or all from xyzw, and only the parts the thing has: UV.z doesn’t exist.
  • You can’t change one part of a variable: c.r = 1.0 isn’t a line. Make a new color instead: c = RGBA(1.0, c.g, c.b, c.a).
  • USE lines come before WHEN DRAWING, and there’s one WHEN DRAWING.
SCREEN 320, 240
SHADER "swizzled"
    WHEN DRAWING
        red = OWNTEXTURE(UV).r
        SET COLOR = RGBA(red, 0.0, 0.0, 1.0)
    END WHEN
END SHADER

How many

WhatHow many
Numbers in the settings, a USE NUMBER one and a USE COLOR four64
USE IMAGE pictures4
Parts in a swizzle4

What I do for you

  • Alpha. On a sprite, the alpha your shader hands back is multiplied by the sprite’s own, so fading a sprite works with any shader on it.
  • Frames. On an animated sprite, UV, PX and OWNTEXTURE are the frame’s, not the sheet’s.
  • Edges. Reading a picture outside 0 to 1 gets you its edge.
  • Pixels, not blurs. Reading a picture between two of its pixels gets you the nearer one, not a blend. That’s what keeps pixel art crisp, and why a very slow scroll moves in steps.