a shader guide

every pixel
asks a question

00

a new kind of drawing

A mark on a page – drawn from nothing, by you – is one of our earliest experiences of creation. You think of a line and your hand makes it. The translation from thought to mark is almost nothing. Immediate. Physical. Yours.

The computer introduced a different bargain. To make a mark, you describe it. A line becomes two points. A circle becomes a center and a radius. You lose something of the body, but you gain something else entirely: the ability to describe a thing once and have it happen a thousand times, each instance slightly different, each one obeying the same rule. The computer is not a faster hand. It is a different kind of tool, with a different kind of fluency.

For most of computing history, drawing on a screen meant giving instructions in order. Go right. Draw a line. Make a circle here. The computer followed along, one step at a time, like a very obedient and very fast hand.

But in the 1980s, as rendering images grew more ambitious – lighting, shadows, the way glass catches the sun – a different idea emerged in film studios. What if each pixel decided for itself?

Instead of one long list of instructions, you write a single small program. And then every pixel on the screen runs that program simultaneously, each one asking: given where I am, what should I look like? A million tiny questions, answered all at once.

This is what a shader is.

The word comes from its original purpose – shading surfaces, simulating light – but shaders have grown far beyond that. It took another twenty years for that idea to become fast enough to escape the render farm and reach the screen in your hand. Today they generate the skies in video games, the transitions between scenes in films, the animated interfaces on your phone. Almost every image rendered by a modern screen passes through one.

And yet shaders have stayed strangely hidden. The tools for writing them are made by and for engineers. The learning curve is steep and arcane. This is a loss, because the idea at the heart of a shader is not an engineering idea. It is a design idea. An art idea. The question what should this pixel look like? is the same question a painter asks, a photographer asks, a designer asks – just asked very, very fast, and all at once.

This guide is an attempt to bring shaders into the light. We start with a single pixel. We ask it one question. And we go from there.

01

one answer

A screen is made of pixels. Each pixel is a tiny point of light, and each one can be told how bright to shine, anywhere from 0 (completely dark) to 100 (completely bright).

In this guide, you will write small programs that answer the pixels’ questions. Each program is a set of instructions, written as plain words and numbers. There is no punctuation to memorize. No strange symbols. Just instructions, one per line.

The first instruction you will learn is answer. It is the answer to the pixel’s question: what should I look like? It takes a single number – the brightness level you want – and sets the pixel to that value. Written like this:

answer 50

That is a complete program. One instruction. One pixel. Try it. Change the number in the editor below and press run – the square on the right is your pixel, scaled up so you can see it clearly.

program
output

What does 0 look like? What about 100? What about 42?

02

where are you?

In the last chapter, every pixel would get the same answer. One number, one brightness, one result: the program didn’t need to think about which pixel it was talking to, because it treated them all identically.

But pixels are not identical. Each one occupies a specific place on the screen, and that place is part of what it is.

We describe position in two directions. Left to right, we call <x>. Bottom to top, we call <y>. Every pixel has both, a unique address, a location that belongs to it alone. We’ll start with looking at <x>.

<x> →
0 25 50 75 100

Every pixel comes with an <x> already given. You don’t set it, it comes with the position. On a grid five pixels wide, <x> runs from 0 on the left to 100 on the right. The pixel in the middle has an <x> of 50.

This means you can use <x> in your answer. When you run the program, every pixel substitutes its own <x> into the program: the pixel on the left edge uses 0, the one in the middle uses 50, the one on the right uses 100.

Try it below on a single pixel. Its <x> is fixed at 50, sitting in the middle. Nothing very surprising yet.

program
output

But that program is no longer just a number. It is a rule. And rules only show their nature when applied to more than one thing.

Everything that follows in this guide is that one idea, growing.

Let’s run the same program on a 5×5 grid. Each pixel gets its own answer.

program
output

But a pixel knows more than just its left-right position. It also knows how far up or down it is. This is <y>.

↑
<y>
100 75 50 25 0

A pixel at the very bottom has a <y> of 0. A pixel at the very top has a <y> of 100. The middle is 50. It works exactly like <x>, just in the vertical direction.

Try it, and notice how the gradient now runs bottom to top instead of left to right. By the way, if you move your mouse over the output canvas, it will show you the coordinate of the pixel you’re hovering over.

program
output

Now you have two coordinates, two things every pixel knows about itself. Between <x> and <y>, a pixel knows exactly where it sits in the grid. No two pixels share the same pair.

Try switching between answer <x> and answer <y> to see the difference. Then try answer 50 again, where every pixel gives the same answer, because the rule ignores position entirely.

03

combining things

So far, each program has been a single value: a number, <x>, or <y>. But you can combine values using arithmetic: +, -, *, and /.

This is where things get interesting. When you write answer <x> + <y>, each pixel adds its own <x> to its own <y>. A pixel in the bottom-left corner gets 0 + 0 = 0. A pixel in the top-right gets 100 + 100 = 200 (which is clamped to 100, because brightness can’t exceed that).

The result is a diagonal gradient. Light gathers in one corner, darkness in the other.

Try it. Then try answer <x> - <y>. Or answer <x> * <y> / 100. Each expression produces a different pattern, the direct visual consequence of a rule.

program
output

Note that you can use parentheses to control the order of operations, just as you would on paper: answer (<x> + <y>) / 2.

Programs can also contain comments, little notes to yourself. Anything after // on a line is ignored by the pixel.

answer <x> + <y> // diagonal gradient

Comments change nothing about the output. They are for you, to remember what you were thinking, or to explain something to someone else.

04

when are you?

Everything so far has been still. You write a program, you run it, and the canvas shows you a single, frozen moment. But a screen is not a photograph. It can change.

There is a new value available in your programs: <time>. Unlike <x> and <y>, which stay fixed for each pixel, <time> increases continuously, counting upward from the moment you press run. It rises quickly: about 50 units per second.

The canvas will flash from black to white in about two seconds, then stay white, because brightness is clamped at 100 and time keeps climbing past it. A single flash, then nothing.

program
output

Time runs away. That is its nature. To make something repeat, you need a way to wrap a number around: 101 becomes 1 again, 201 becomes 1 again, forever.

This is what % does. It is called the remainder operator, also called modulo. It gives you the leftover after division.

137 % 100 is 37, because 137 divided by 100 leaves a remainder of 37.
100 % 100 is 0.
250 % 100 is 50.

When you write <time> % 100, the result counts from 0 up to 100, then jumps back to 0 and starts again. A cycle. A pulse. About once every two seconds.

This works for negative numbers too: -30 % 100 is 70 – the value wraps around from the other end. That wrap is what keeps a leftward-moving wave seamless.

program
output

Now the canvas breathes, from darkness to light, over and over. Every pixel gives the same answer at the same moment, so they all pulse together in unison.

But you know how to break that unison. You have <x> and <y>. What happens when you add position to time?

Try answer (<x> - <time>) % 100. The gradient begins to scroll, each pixel’s answer offset by where it sits, so the wave moves across the canvas.

Try answer (<x> + <y> - <time>) % 100. A diagonal wave.

Change the number after % to change the speed and scale of the pattern. A smaller number means tighter, faster cycles. A larger number means slower, broader ones.

program
output
05

naming things

You’ve been tuning programs by changing numbers directly. But a number on its own says nothing about what it does. Give it a name and it starts to explain itself.

Use set to give a number or an expression a name:

set speed 2

After that line, speed carries the value 2. You can use it anywhere you would use a number. When you read <time> * speed, you know what that multiplication is doing. The name speed is yours to choose – you could call it s, rate, or anything else you like.

program
output

A faster wave. The name speed makes it easy to adjust: change it in one place and the whole pattern follows. Notice that speed holds the same value for every pixel – a constant, just with a label.

The next program uses set differently. dx and dy depend on <x> and <y>, so each pixel gets its own values for them. That’s what lets two named ideas compose into a shape.

program
output

A soft dome. dx and dy take a different value at every pixel: large at the edges, zero at the center. Squaring them and adding turns that pair into a single number: how far each pixel sits from the center.

Try changing the / 50. A smaller number darkens the edges faster; a larger one spreads the dome wider. Replace <x> - 50 with 0 and the dome flattens into a horizontal band, brightest across the middle and fading toward the top and bottom.

This is what naming things unlocks. Instead of one long formula, you build up in steps. Each step has a name that says what it means, and the final line reads almost like a sentence.

06

tools of the trade

Some operations come up again and again: making a negative number positive, finding the larger of two values, creating a smooth wave. These are built in as functions.

A function takes a value and gives back a new one. You use it by writing the function name followed by the value, or an expression in parentheses.

The first function: positive. It gives the absolute value, the distance from zero. positive -30 is 30, and positive 30 is also 30.

In the editor below, positive measures each pixel’s distance from the center along two axes. The result is a diamond shape, with pixels near the center bright and those at the edges dark.

program
output

One thing to notice: positive <x> - 50 means “absolute value of <x>, then subtract 50”: a function only takes the single value immediately after it, so this is read as (positive <x>) - 50. If you want to apply positive to a whole expression, use parentheses: positive (<x> - 50).

Now for something smooth. wave produces a wave, a value that rises and falls in a continuous curve. wave takes an input from 0 to 100 (one full cycle) and gives back a value from 0 to 100. At 0 the output is 50, at 25 it peaks at 100, at 50 it returns to 50, and at 75 it dips to 0.

→

Try answer wave <time> below, for a slow, gentle pulse. Then try answer wave <x> for a spatial wave, or answer wave (<x> + <time>) for a wave that scrolls.

program
output

And then there are some functions that take two values. lowest gives the smaller of two values, highest the larger.

lowest a b means “the lower of a and b”, so lowest 20 80 is 20.
highest a b means “the higher of a and b”, so highest 20 80 is 80.
If you need to pass a longer expression, wrap it in parentheses: highest (<x> - 50) (<y> - 50).

In the editor below, highest turns the diamond into a square. The diamond used dx + dy, adding both distances. Replacing the sum with highest measures only the greater distance. The result is a square boundary instead of a diamond.

program
output

One more function: distance. It takes two values – an x coordinate and a y coordinate – and returns the straight-line distance from the current pixel to that point.

distance 50 50 gives how far each pixel sits from the center. Unlike positive (<x> - 50), which only measures horizontal separation, distance accounts for both axes at once. The result is a true radial gradient.

Feed that into wave together with <time>, and the rings ripple outward from the center.

program
output

A few more functions will quietly serve you for the rest of this guide – worth meeting now, even though their moment comes later. floor and round snap a value to a whole number: floor always rounds down, round rounds to the nearest integer. flip x inverts by returning 100 - x, so bright becomes dark and vice versa. And sqrt is the square root: sqrt 25 is 5, sqrt 100 is 10.

07

on the edge

So far every program has produced a smooth, continuous result. Every pixel’s answer has been a function of its position or time, varying gradually across the canvas. But most images contain edges: places where something stops and something else begins. How do you make an edge?

In most languages you would reach for an if/else: if x is less than 50, return black; otherwise, return white. But this language has no if/else. Every pixel runs the same program; there is no branching.

Instead, you express the idea as arithmetic. cut takes a value and a threshold. If the value is below the threshold, it returns 0. If the value is at or above the threshold, it returns 100. The result snaps, but it is still just a number.

program
output

A hard vertical line, expressed as a value, not a branch. And because it is a value, you can use it in arithmetic.

The real power of cut is that it gives you a mask: a number that is either 0 or 100. Multiply your answer by a mask and you have masked it. A circle can be drawn this way: compute the distance from the center, cut it at the desired radius, multiply. The shape is the multiplication.

One detail: because a mask is 100 rather than 1, divide by 100 after multiplying – answer value * mask / 100. (For simple on/off images the division can be skipped, since brightness is clamped at 100 anyway – that’s what the rectangle below does.)

program
output

A dark disc on a bright background. d is the distance from the center, the value being tested. 30 is the threshold. Every pixel within 30 units of the center falls below it and answers 0. Every pixel beyond answers 100.

Now combine two cuts. cut d 20 snaps at radius 20; cut d 30 snaps at radius 30. Both are 100 beyond their threshold, so their difference is 100 only in the ring between them.

program
output

A rectangle works the same way: cut in one axis, then the other, and multiply. Each cut carves a boundary; their product is the region where both are active.

program
output

So far every edge has been perfectly sharp, a sudden jump from 0 to 100. But many shapes need softer boundaries: a glow, a shadow, a smooth edge.

fade is like cut but with a transition zone. It takes a value and two thresholds: fade value threshold1 threshold2. Below threshold1 it returns 0. Above threshold2 it returns 100. Between the two thresholds, it glides smoothly from 0 to 100 along a gentle S-curve.

If you give the higher threshold first, the ramp reverses: 100 below, 0 above. That is what the soft circle below does – pixels close to the center (small d) get 100, pixels beyond 35 get 0.

Try the soft circle below. Adjust the two threshold values and feel how they control the hardness of the edge.

program
output

A circle with a soft, glowing edge. When the two edges are far apart, the transition is wide and gentle. When they are close together, the edge is nearly sharp. When they are equal, it behaves like cut.

You can animate the edges too. Below, fade makes a circle breathe, its rhythm driven by <time>.

program
output

In conventional programming, shape and logic are separate concerns. Here they are the same thing. A shape is a mask is a number. You do not draw a circle. You compute whether each pixel is inside one. This is the shader way of thinking about form.

Now that you can compute shapes, the next question is: what do you do with them? The simplest use of a mask is to switch between two values; switching sharply at a threshold is just cut. What if you want to mix two things together, in any proportion?

blend a b t interpolates between two values. When t is 0, it returns a. When t is 100, it returns b. In between, it returns a proportional mix.

Think of it as a crossfader: at one extreme you hear only the first signal, at the other extreme only the second, and anywhere in between you hear both.

program
output

The left side of the canvas shows the slow wave; the right side shows the fast one. In between, they blend smoothly. The mixing amount is just <x>, a number that goes from 0 to 100 across the canvas.

08

your own questions

You have used built-in tools like wave, positive, and distance, each one taking an input and giving back a result. But what happens when you need a tool that does not exist yet?

You can define your own. In this language they are called questions: you ask one, and it gives you an answer.

program
output

The word question starts a definition. After it comes a name (here, halve), and then any inputs it needs, separated by spaces. The body goes inside { }, and the answer inside returns the result.

Notice that answer means something different inside a question: it is the question’s private result, not the pixel’s brightness. The answer at the bottom, outside any question, still sets the pixel.

A question can take more than one input. Try this one that averages two values.

program
output

Questions can use everything you have learned: variables, masks, and even other questions. And they have their own private workspace: a set inside a question stays inside; it cannot leak out and affect the rest of your program.

The real power comes when one question uses another. spot draws a filled disc. ring calls it twice – once at the outer radius, once at the inner – and subtracts. One disc punched through another.

program
output

Once you can package a calculation into a question, you can reuse it as many times as you like, with different inputs each time.

One more question that can help you make decisions:

program
output

choose value threshold a b returns a when value is below the threshold, and b when it is at or above it. It is exactly like an if/else, expressed as a number.

This pattern is particularly useful in programs that carry information from one frame to the next, where you need to decide which of two values a pixel should hold based on a condition. You will see it again in later chapters.

09

reach in

Until now, every program you have written runs on its own. You set it going and watch. What if you could reach into the canvas and change things while the program runs?

Two new variables: <mousex> and <mousey>. They track the pointer’s position over the output canvas, using the same 0–100 coordinate system as <x> and <y>. Before you interact, both start at 50, centered on the canvas. Once you move over the canvas, they remember the last position.

Run the program below, then move your pointer over the output.

program
output

A bright band that follows the cursor left and right. Now use distance to measure from the pointer instead of a fixed point.

program
output

A spotlight that follows your pointer. Try wave on the distance to get interactive ripples.

Add <time> and the ripples radiate outward from wherever you point. Try changing the multiplier or subtracting <time> to reverse direction.

There is one more mouse variable: <mousedown>. It is 100 when you are holding the mouse button, and 0 when you are not. Use it to switch between two different states – press and hold to see the difference.

program
output

A spotlight when you’re not pressing, ripples when you are. <mousedown> is just a number – it can go anywhere a number goes.

10

nature’s brush

Everything you have made so far is precise. Circles are perfect. Waves repeat forever. Gradients flow smoothly from one value to another.

But look at the world outside the screen: tree bark, coastlines, clouds, the surface of a stone. There is structure, but it is never exactly the same twice. Nature’s textures are organic: smooth up close, rough from a distance, and full of surprises at every scale.

We need a new kind of function. noise takes three values and gives back a smooth, unpredictable number, mostly between 0 and 100. The same inputs always give the same output, but nearby inputs give nearby outputs, creating a landscape of gentle hills and valleys.

noise wave

Where wave repeats the same curve forever, noise wanders, never repeating, never sharp.

program
output

An organic texture, nothing like wave’s perfect ripples. No two regions look the same, yet the whole surface is smooth and continuous.

Try changing the scale of the detail by multiplying the inputs, like this: noise (<x> * 2) (<y> * 2) 0. A higher multiplier means finer, more rapid changes.

But noise takes three values. The third dimension can make the noise change its shape gradually, and therefore it’s perfect for <time> to make the noise evolve smoothly, like clouds drifting across the sky.

program
output

Noise gives one scale of detail, a gentle rolling landscape. But nature has texture at every scale. A mountain range has peaks, which have boulders, which have rocks, which have pebbles. Each scale adds finer detail on top of the last.

You can build this yourself: layer the same noise at different scales, making each layer smaller and quieter. Multiply the input to zoom in, and divide the result to make it subtler.

+++=

This layering technique is called fractal noise (or fractal Brownian motion). Shader artists use it all the time.

program
output

Now combine everything you know. Use fractalnoise (<x> + <time>) 0 0 as a horizon line and cut to draw sky above and land below, a scrolling mountain landscape.

program
output

There is so much to explore from here. Try wave (2 * noise <x> <y> <time>) for plasma. Try cut (fractalnoise <x> (<y> / 2 - <time> * 2) 0) <y> for rising fire. Try thresholding noise at different heights to build a layered terrain map. Or feed <mousex> and <mousey> into the noise to sculpt textures by hand.

11

making memories

Every chapter so far, the pixel has answered its question fresh. Each pixel answers from scratch every frame. It knows its position, the time, the mouse – but nothing about what it was on the previous frame. However many frames have run, each one is computed as if it were the first.

But there is something new the pixel can know: what it was on the last frame.

remember <x> <y> reads the brightness at position <x>, <y> from the previous frame, the image that was on the canvas one step ago. You can read your own position, or any other pixel’s position.

The simplest use: mix the current answer with the previous one.

The canvas is no longer stateless. It accumulates. It remembers.

Try the program below. Move your pointer over the canvas. You are drawing, and the marks linger, fading slowly into darkness.

program
output

The weight of the mix controls the length of the memory. When you multiply the previous value by something close to 100 (like 99), the trail fades slowly, a long and lingering memory. When you multiply by something smaller (like 90), it fades quickly. A short, snappy response.

Add <mousedown> and the trail becomes a brush: paint only applies when the button is held.

program
output

But remember does not have to read its own position. A pixel can look at what its neighbors were on the last frame. When it averages itself with its four neighbors ((<x> + 1) <y>, (<x> - 1) <y>, <x> (<y> + 1), <x> (<y> - 1)), heat spreads. Ink bleeds.

This is diffusion. Try it below: move your pointer to paint brightness onto the canvas, then watch it dissolve outward.

program
output

Diffusion smooths. A nonlinear reaction sharpens, pushing values toward black or white. When these two forces compete, neither wins, and organic boundaries emerge. Press run below and watch the noise sort itself into blobs.

program
output

The patterns on animal skins, the branching of corals, the whorls of a fingerprint – all of them grow from this same principle. It has a name: reaction-diffusion.

Now try reading the previous frame at warped coordinates. If you offset the lookup with wave, the image folds into itself, a feedback loop that creates endlessly evolving patterns.

program
output

Reading at a different position doesn’t just blend or diffuse: it transports. Each frame, content moves a fraction of a pixel, then the shifted content moves again. Small offsets compound into large, coherent drifts. The canvas is now a medium, carrying patterns through space as well as through time.

12

look out

Everything so far has been self-contained. The pixel’s world has been mathematics, position, time, the mouse. Nothing from outside the screen has entered the picture.

eye <x> <y> opens a window to the world. Whatever the device’s camera sees becomes available as a value, sampled at any coordinate. Just like remember, but reading from the live camera feed instead of the last frame.

The simplest use: answer eye <x> <y>

A live grayscale feed. Underwhelming for about one second, then you realize you are writing a program that processes real light in real time.

Your browser will ask for camera permission when you press run. If you decline, the examples use a short looping video instead – everything still works.

program
output

Everything you have learned now applies to a real image. Threshold it with cut for hard black and white, like a photocopy left in the sun:

program
output

The camera does not have to sample straight. Offset the sample coordinates with wave and the image wobbles, a wave displacement animated with time:

program
output

Compare each pixel to its neighbor and brighten or darken where they differ. That is edge detection, the same principle used in computer vision:

program
output

The pixel is still just asking the same question it always has – what should I look like? – but now the answer can contain the world.

Try combining the camera with everything else: remember for trails, noise for texture, wave for animation. The camera is just another input, another thing each pixel knows.

program
output
13

the wider world

You have come a long way. From answer 50 to a program that processes the world through a camera lens.

Pause and notice what actually happened: you learned to think in a completely new way. Not sequentially, not imperatively, but in parallel, as rules rather than instructions. Every program you wrote was a single description applied simultaneously to every pixel on the canvas. That shift in thinking is the real achievement of this guide.

You are not alone in this pursuit. There is a remarkable subculture called the demoscene that has been doing exactly this since the 1980s. Groups of programmers and artists compete to produce the most extraordinary real-time visuals under extreme constraints, sometimes an entire animated scene with music in 64 kilobytes. This is where much of the craft of shader programming was developed, passed down not through textbooks but through released executables and shared wonder.

There are artists who have dedicated their lives to this medium. Inigo Quilez has spent decades making extraordinary images from pure mathematics: signed distance fields, implicit surfaces, entire worlds built from equations. His writing has taught a generation of shader artists. The creative coding community more broadly (Processing, p5.js, the lineage that runs from John Maeda through Casey Reas and Ben Fry to thousands of artists working today) is part of a much larger conversation about computation as a creative medium.

Real-time is a specific condition. The work exists in time, responds to the viewer, cannot be fully experienced as a static object. This connects it to performance, to installation art, to music. A shader running on a screen is closer to a musical score being performed than to a painting hanging on a wall – it is a set of rules that produces an experience, and the experience is never exactly the same twice.

This guide began with the observation that drawing by hand is one of the first things we learn to do. The computer offered a different bargain: describe, don’t draw. You have now spent time on the other side of that bargain, and, I hope, found that something was gained as well as lost. The fluency is different. But it is fluency.

Here is where to go next:

Thank you for reading. Every pixel is still asking. You know how to answer.

vocabulary

answer value
Sets the pixel’s brightness. Takes a value from 0 (black) to 100 (white). Values outside this range are clamped.
<x>   <y>
The pixel’s position. (0, 0) at the bottom-left corner, (100, 100) at the top-right corner.
+   -   *   /   %
Arithmetic operators. Add, subtract, multiply, divide, remainder. Use parentheses ( ) to control order of operations. The remainder operator % gives the leftover after division, useful for creating repeating cycles.
// comment
A comment. Everything after // on a line is ignored. Use comments to annotate your programs.
<time>
A value that increases continuously from the moment you press run. Rises about 50 units per second. Use % to wrap it into repeating cycles.
set name value
Creates or updates a variable. After set d <x> - 50, the name d holds the value of <x> - 50 for this pixel. Names can be reassigned.
positive a
Absolute value – distance from zero. positive -30 is 30, positive 30 is also 30.
wave a
Wave function. Input from 0 to 100 maps to one full cycle; output ranges from 0 to 100. At input 0, wave returns 50; it peaks at 100 when the input is 25. (This is a sine wave, scaled into the 0–100 range.)
lowest a b   highest a b
lowest returns the smaller of two values, highest returns the larger.
distance x y
Returns the distance from the current pixel to the point (x, y). distance 50 50 measures how far from the center.
floor a   round a
floor rounds down to the nearest integer. round rounds to the nearest integer. Useful for snapping values to grid steps.
flip a
Returns 100 minus the input. flip 30 is 70. Useful for inverting brightness or mirroring coordinates.
sqrt a
Square root. sqrt 64 is 8.
cut value threshold
Returns 0 if value is below threshold, 100 if at or above. Used to create hard edges and binary masks.
fade value threshold1 threshold2
Returns 0 below threshold1, 100 above threshold2, with a smooth S-curve transition between. Used for soft edges, glows, and antialiased shapes.
blend a b t
Interpolates between a and b based on t. When t is 0, returns a; when 100, returns b; in between, mixes proportionally. Combine with cut to implement branching.
question name [params…] { … }
A custom function. Call it by name, like any other function. Inside the body, answer returns a value, instead of setting the pixel. Parameters are private inputs, set inside a question stays local. The question can also read the global pixel variables <x>, <y>, <time>, etc. Names may end in ?, which reads nicely for yes/no questions: question inside? x y { … }.
<mousex>   <mousey>
The pointer’s position over the output canvas, in the same 0–100 coordinate system as <x> and <y>. Starts at 50 (center) and remembers the last known position when the pointer leaves. While a program that uses the mouse is running, the canvas re-renders continuously.
<mousedown>
100 while the mouse button is held over the canvas, 0 otherwise. Combine with <mousex>, <mousey>, and remember to make interactive, paint-like programs.
noise x y t
Smooth, organic noise returning a value mostly from 0 to 100. The same inputs always give the same result, but nearby inputs give nearby results. Multiply inputs to control the scale of detail.
remember x y
Reads the brightness of the pixel at position (x, y) from the previous frame. Enables trails, diffusion, and feedback effects.
eye x y
Returns the brightness seen by the device’s camera at position (x, y), in the same 0–100 coordinate system. Requires camera permission.

Playground-only features

<unit>
The distance between adjacent pixels in the 0–100 coordinate system. At the default resolution of 100, <unit> is 1. At higher resolutions it shrinks proportionally, so remember (<x> + <unit>) <y> always refers to the immediate neighbor.
<frame>
A counter that increments by 1 each frame, starting from 0 when you press run. Useful when you need an exact integer step count rather than time.
<resolution>
The current resolution: the number of pixels along each edge. Useful for writing programs that adapt to the resolution slider.